C# 为什么要将发送方闭包与PipeTo()一起使用?
下面是在Akka.NET中使用C# 为什么要将发送方闭包与PipeTo()一起使用?,c#,akka,akka.net,C#,Akka,Akka.net,下面是在Akka.NET中使用PipeTo()的示例: Receive<BeginProcessFeed>(feed => { //instance variable for closure var senderClosure = Sender; SendMessage(string.Format("Downloading {0} for RSS/ATOM processing...", feed.FeedUri)); //reply bac
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);
});
在这个示例和文档中,都说这里必须使用闭包。但我不认为有任何理由这样做
如果我们使用了ContinueWith()
,那么在continuation中使用闭包是合理的,但不能作为PipeTo()
参数
我错过了什么吗?这里有两件事需要理解:
Sender
不是静态属性。返回正在处理的当前邮件的发件人。每次上下文从邮箱获取新邮件时,返回的值都会更改PipeTo
是一个延续,当该延续在线程池上执行时,调用Sender
将访问与启动任务完全相同的IActorContext
对象。无法保证上下文中当前的发送方
是相同的,因为自任务启动后,新消息被推送到参与者中进行处理因此,我们将
Sender
的值缓存在一个局部变量中,以确保无论何时执行PipeTo
时,我们的目标都是正确的iactoref
。当编译器在闭包上下文中捕获“this”时,就会出现您描述的问题。例如,当我们在lambda表达式中使用“this”成员(如Sender)时,就会发生这种情况。但在这里,我们只是将参数传递给PipeTo()方法,并且没有创建闭包。Sender是一个上下文敏感的方法—每次参与者收到消息时,它的值都会发生变化。如果Sender的当前值未缓存在局部变量中(使用PipeTo时会关闭),则很有可能Sender调用返回的值与预期的参与者不同。我们已经多次重复此错误:p@Aaronontheweb:“如果发送方的当前值未缓存在局部变量中,则使用PipeTo时会关闭该局部变量”。这对我来说没有意义:PipeTo所做的不是关闭发送方
属性,而是关闭一个局部变量(参数接收方
),该变量是当前发送方
引用的副本。因此,我认为这与将Sender
属性显式复制到局部变量没有什么不同。@AndrewS。再挖深一点。发送方是静态的,因为它是静态属性的成员。Sender是一个属性,它返回受保护的IActorRef Sender=>Context.Sender;。看看上下文。它受静态上下文保护。继续挖掘,您最终将获得[ThreadStatic]私有静态ActorCell\u current;Petabridge现场PipeTo的官方例子是关于关闭的错误。这根本不是闭包的例子,而是参数传递的例子。仔细阅读结束语。所讨论的变量必须是自由变量。不是参数。您可以轻松地将发送方直接发送到PipeTo,因为它会立即被调用,并与CreateFeedAsync并行运行。别相信我。你自己试试看。
_feedFactory.CreateFeedAsync(feed.FeedUri).PipeTo(Sender);