alp*_*ler 4 c# task-parallel-library async-await tpl-dataflow taskcompletionsource
Lucian在这里讨论了一种模式(技巧3:在任务返回API中包装事件并等待它们).
我试图在一个经常调用的方法上实现它,看起来像下面的设计代码:
public Task BlackBoxAsync()
{
var tcs = new TaskCompletionSource<Object>(); // new'ed up every call
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
DoSomethingStuff();
tcs.SetResult(null);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
我很担心性能,TaskCompletionSource每次通话都是新的(让我们说我每100毫秒调用一次这个方法).
我当时正在考虑使用BufferBlock<T>,认为每次通话都不会重新开始.所以它看起来像:
private readonly BufferBlock<object> signalDone; // dummy class-level variable, new'ed up once in CTOR
public Task BlackBoxAsync()
{
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
DoSomethingStuff();
signalDone.Post(null);
}
catch(Exception exc) { }
});
return signalDone.ReceiveAsync();
}
Run Code Online (Sandbox Code Playgroud)
调用对象会将其称为:
for (var i=0; i<10000; i++) {
await BlackBoxAsync().ConfigureAwait(false);
}
Run Code Online (Sandbox Code Playgroud)
有人对使用有任何想法BufferBlock<T>吗?
无论你使用什么解决方案,如果你await每次调用这个方法都想要一个任务,创建一个新的Task是不可避免的,因为任务不可重复使用.最简单的方法是使用TaskCompletionSource.
所以第一个选择是使用a BufferBlock(不出所料,创建一个新TaskCompletionSource的ReceiveAsync)的首选IMO
更重要的是,您的代码似乎只是将工作卸载到ThreadPool并返回表示该工作的任务.你为什么不用简单的Task.Run?
public Task BlackBoxAsync()
{
return Task.Run(() => DoSomethingStuff());
}
Run Code Online (Sandbox Code Playgroud)