我在我的软件中使用TaskCompletionSource
将网络数据包分发到async
/ await
方法。因此,在我的代码中,软件需要等待网络数据包从接收处理程序中解复用并移交给方法async Wait()
。每秒可以有很多很多数据包,我决定是否要将数据包推送到TaskCompletionSource
或将其放入Queue
。因此,每当没有TaskCompletionSource
我将创建一个新的,这导致一个新的Task
对象。
根据这个问题Do I need to dispose of a Task?和根据这个博客Parallel Programming with .NET Task
s不需要是Dispose
d。但是,我有时会每秒实例化数千个TaskCompletionSource
。链接博客中的详细答案也说,Task
可能会在内部使用WaitHandle
。现在我有强烈的感觉,我的情况就是确切的情况,我应该在Dispose
的任务中使用TaskCompletionSource
。
这就是我等待新数据包的方式。这个方法将使用await
调用,也可以并行调用:
public async Task<Packet> Wait()
{
Packet packet;
lock (sync)
if (packets.TryDequeue(out packet))
return packet;
else
waiter = new TaskCompletionSource<Packet>();
return await waiter.Task;
}
我从网络处理程序推送数据包的方法如下所示:
public void Poke(Packet packet)
{
lock (sync)
if (waiter == null)
packets.Enqueue(packet);
else
waiter.SetResult(packet);
}
我在.NET Core> = 2.2。该博客文章指出WaitHandle
的行为在.NET 4.5中也发生了变化。
问题:我是否需要在此特定情况下处理Task
s?我是否会创建许多Handles
,如果我没有Dispose
TaskCompletionSource
创建的任务收到沿此代码路径的许多数据包?这是博客条目警告我的情景吗?
请不要告诉我,这种方法是一个糟糕的选择,只要你不能告诉我一个更好的方法与async
/ await
模式非常兼容,并且能够将这些数据包分发给各种选定的听众。请不要告诉我,因为许多网络数据包而创建许多对象通常是一个坏主意。
这是博客条目警告我的情景吗?
“我需要处理这个Task
吗?”的问题只能通过任务的消耗来回答。特别要考虑博客文章中的这句话:
分配WaitHandle的唯一方法是,如果你明确要求Task的IAsyncResult.AsyncWaitHandle,那应该是非常罕见的。
Reed's answer当时是正确的,但不再是继续使用AsyncWaitHandle
的情况。这些天,没有任何东西会隐式使用AsyncWaitHandle
,所以你应该只考虑Dispose
ing Task
s,如果你的消费代码将任务视为IAsyncResult
并访问AsyncWaitHandle
属性。即便如此,你应该只考虑处理它们;这不是绝对必要的。
请不要告诉我,这种方法是一个糟糕的选择,只要你不能告诉我一个更好的方法与async / await模式非常兼容,并且能够将这些数据包分发给各种选定的侦听器。
我建议将async兼容的生产者/消费者队列构建为单独的类型;我认为这有助于您的代码更清晰。您可以使用use BufferBlock<T>
,async queue type from my AsyncEx library,或使用异步兼容的监视器构建您自己的。
此外,如果您经常期望您的Wait()
方法已经有可用的数据包,那么请考虑使用ValueTask<T>
。