正如Stephen Toub在这篇文章中所解释的那样,当您向ActionBlock提交消息时,可以在调用ActionBlock.Post之前执行ExecutionContext.Capture,将同时包含消息和ExecutionContext的DTO传递到块中,然后在消息处理委托内使用ExecutionContext.Run来在捕获的上下文中运行委托:
public sealed class ContextFlowProcessor<T> {
private struct MessageState {
internal ExecutionContext Context;
internal T Value;
}
private readonly ITargetBlock<MessageState> m_block;
public ContextFlowProcessor(Action<T> action) {
m_block = new ActionBlock<MessageState>(ms =>
{
if (ms.Context != null)
using (ms.Context) ExecutionContext.Run(ms.Context, s => action((T)s), ms.Value);
else
action(ms.Value);
});
}
public bool Post(T item) {
var ec = ExecutionContext.Capture();
var rv = m_block.Post(new MessageState { Context = ec, Value = item });
if (!rv) ec.Dispose();
return rv;
}
public void Done() { m_block.DeclinePermanently(); }
public Task CompletionTask { get { return m_block.CompletionTask; } }
当消息处理程序内部的逻辑是同步的时,它能够很好地工作。但是,我该如何在捕获的ExecutionContext上运行一个异步逻辑?我需要像这样的东西:
m_block = new ActionBlock<MessageState>(async ms =>
{
// omitting the null context situation for brevity
using (ms.Context)
{
await ExecutionContext.Run(ms.Context, async _ => { callSomethingAsync(ms.Value) });
}
});
显然,这段代码不能编译,因为ExecutionContext.Run不支持异步委托(而ActionBlock却支持)-那我该怎么办呢?
DeclinePermanently
,属性CompletionTask
)。因此,提供的信息可能不准确。我的实验表明,默认情况下会捕获ExecutionContext
,而ContextFlowProcessor
的行为与简单的ActionBlock
相同。您有展示差异的示例吗? - Theodor Zouliasasync/await
关键字在幕后使用了ExecutionContext
。async/await
只是一些基础设施,帮助模拟异步编程中的同步语义。因此,当您使用ExecutionContext
时,这意味着您需要手动处理事情。我认为,在它们自己基于ExecutionContext.Run
并且正在使用它的情况下,ExecutionContext.Run
支持async/await
是没有意义的。 - Ali Zeinali