TaskCompletionSource 生成的任务是否需要 Dispose()d?

Do Tasks generated by TaskCompletionSource need to be Dispose()d?

我在我的软件中使用 TaskCompletionSource 将网络数据包分发到 async/await 方法。所以在我的代码中,软件需要等待网络数据包从接收处理程序中解复用并移交给方法 async Wait()。每秒可能有很多很多数据包,我正在决定是将数据包推送到 TaskCompletionSource 还是放入 Queue。因此,只要没有 TaskCompletionSource,我就会创建一个新的,这会导致一个新的 Task 对象。

根据这个问题 Do I need to dispose of a Task? and according to this blog Parallel Programming with .NET Tasks 不需要 Disposed。但是,我有时每秒实例化数千 TaskCompletionSource。链接博客中的详细答案还说,Task 可能在内部使用 WaitHandle。现在我有一种强烈的感觉,我的情况就是这样,我应该在 TaskCompletionSource.

的任务上使用 Dispose

这就是我等待新数据包的方式。此方法将被调用 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 吗?我是否会创建许多 Handles,如果我不 Dispose TaskCompletionSource 在收到沿此代码路径的许多数据包时创建的任务?这是博客条目警告我的情况吗?

请不要告诉我这个方法是一个糟糕的选择,只要你不能告诉我一个更好的方法非常兼容 async/await模式,并且还能够将这些数据包分发给各种选定的侦听器。也请不要告诉我,因为有很多网络数据包而创建很多对象通常不是一个好主意。

Is this the scenario the blog entry warned me about?

"do I need to dispose this Task?" 的问题只能通过任务如何消耗 来回答。特别是,请考虑博客 post:

中的这句话

the only way the WaitHandle will be allocated is if you explicitly ask for the Task’s IAsyncResult.AsyncWaitHandle, and that should be quite rare.

Reed's answer 在当时是正确的,但不再是延续使用 AsyncWaitHandle 的情况。如今,没有什么会隐含地使用 AsyncWaitHandle,所以如果 你的消费代码 将任务视为一个任务,你应该只考虑 Disposeing Tasks IAsyncResult 访问 AsyncWaitHandle 属性。即便如此,您也只应考虑 处理它们;严格来说 没有必要 .

Please refrain from telling me, that this method is a bad choice as long as you can't tell me a better method being very compatible to async/await pattern and also being able to distribute those packets to various selected listeners.

我建议构建一个异步兼容的 producer/consumer 队列作为一个单独的类型;我认为这会帮助您的代码更清晰。您可以 use BufferBlock<T>, an async queue type from my AsyncEx library,或使用兼容异步的监视器构建您自己的监视器。

此外,如果您经常期望您的 Wait() 方法已经有可用的数据包,请考虑使用 ValueTask<T>