使用 TaskCompletionSource 与 BufferBlock<T> 包装事件
Wrapping events with TaskCompletionSource vs. BufferBlock<T>
Lucian 在这里讨论了一种模式 (Tip 3: Wrap events up in Task-returning APIs and await them)。
我正在尝试在一个经常调用的方法上实现它,该方法看起来类似于下面的人为代码:
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;
}
我担心性能,因为每次调用都会更新 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();
}
调用对象会这样调用它:
for (var i=0; i<10000; i++) {
await BlackBoxAsync().ConfigureAwait(false);
}
有人对使用 BufferBlock<T>
有任何想法吗?
无论您采用何种解决方案,如果您希望在每次调用此方法时都 await
一个任务,那么创建一个新的 Task
是不可避免的,因为任务不可重用。最简单的方法是使用 TaskCompletionSource
.
所以在我看来,第一个选项比使用 BufferBlock
更可取(不出所料,creates a new TaskCompletionSource
on ReceiveAsync
)
更重要的是,您的代码似乎只是将工作卸载到 ThreadPool
和 return 代表该工作的任务。你为什么不使用简单的 Task.Run
?
public Task BlackBoxAsync()
{
return Task.Run(() => DoSomethingStuff());
}
Lucian 在这里讨论了一种模式 (Tip 3: Wrap events up in Task-returning APIs and await them)。
我正在尝试在一个经常调用的方法上实现它,该方法看起来类似于下面的人为代码:
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;
}
我担心性能,因为每次调用都会更新 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();
}
调用对象会这样调用它:
for (var i=0; i<10000; i++) {
await BlackBoxAsync().ConfigureAwait(false);
}
有人对使用 BufferBlock<T>
有任何想法吗?
无论您采用何种解决方案,如果您希望在每次调用此方法时都 await
一个任务,那么创建一个新的 Task
是不可避免的,因为任务不可重用。最简单的方法是使用 TaskCompletionSource
.
所以在我看来,第一个选项比使用 BufferBlock
更可取(不出所料,creates a new TaskCompletionSource
on ReceiveAsync
)
更重要的是,您的代码似乎只是将工作卸载到 ThreadPool
和 return 代表该工作的任务。你为什么不使用简单的 Task.Run
?
public Task BlackBoxAsync()
{
return Task.Run(() => DoSomethingStuff());
}