2015-07-10 15 views
5

下面是Akka.NET使用PipeTo()the official sample爲什麼我應該使用PipeTo()發件人封閉?

Receive<BeginProcessFeed>(feed => 
{ 
    //instance variable for closure 
    var senderClosure = Sender; 
    SendMessage(string.Format("Downloading {0} for RSS/ATOM processing...", feed.FeedUri)); 

    //reply back to the sender 
    _feedFactory.CreateFeedAsync(feed.FeedUri).PipeTo(senderClosure); 
}); 

的問題是,我們爲什麼要在這裏使用Sender關閉?爲什麼不使用:

_feedFactory.CreateFeedAsync(feed.FeedUri).PipeTo(Sender); 

在這個示例和文檔中說它是強制性的在這裏使用閉包。但我沒有看到有任何理由這樣做。

如果我們使用了ContinueWith(),那麼在continuation中使用closure是合理的,但不應該使用PipeTo()參數。

我想念什麼?

回答

5

兩件事情,瞭解這裏:

  1. Sender不是靜態屬性。 Sender is actually a function on the IActorContext,它返回正在處理的當前消息的發送者。每當上下文從郵箱中收到新消息時,返回的值都會更改。

  2. PipeTo是繼續,當在線程池中執行該繼續時,調用Sender將訪問啓動任務的完全相同的IActorContext對象。無法保證上下文中的當前Sender是相同的,因爲從任務開始以來,新消息被推送到actor中進行處理。

所以我們緩存的Sender值在一個局部變量來保證我們在正確的IActorRef瞄準PipeTo每當執行。

+1

您所描述的問題,當編譯器捕獲在封閉的環境下「本」出現。例如,當我們在lambda表達式中使用「this」成員(如Sender)時會發生這種情況。但是在這裏我們只是將參數傳遞給PipeTo()方法,並且沒有創建閉包。 – alexey

+3

發送者是一種上下文敏感的方法 - 每次演員收到消息時,它的值都會發生變化。如果發件人的電流值不會在一個局部變量,它被當您使用PipeTo在關閉緩存,有一個強大的機會,你的發件人的呼叫可以返回比你預期的演員不同的值。 我們已經能夠複製這種錯誤了無數次:對 – Aaronontheweb

+0

@Aaronontheweb:「如果發件人的電流值不會在一個局部變量,當您使用PipeTo它被關閉了緩存」。這對我沒有意義:PipeTo所做的是不是關閉Sender屬性,而是關閉一個局部變量(參數'recipient'),它是當前Sender引用的副本。因此,我不認爲這與將'Sender'屬性明確複製到局部變量中不同。 –

相關問題