3

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

根据这个问题Do I need to dispose of a Task? 并且根据此博客.NET Task的并行编程不需要Disposed。但是,我有时TaskCompletionSource每秒实例化数千个。链接博客中的详细答案还说,Task可能在内部使用WaitHandle. 现在我有一种强烈的感觉,即我的情况正是如此,我应该DisposeTaskCompletionSource.

这就是我等待新数据包的方式。此方法将被调用,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问题:在这种特定情况下我需要 Dispose吗?我会创建很多Handles吗,如果我没有在接收到沿此代码路径的许多数据包时Dispose创建的任务?TaskCompletionSource这是博客条目警告我的场景吗?

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

4

1 回答 1

4

这是博客条目警告我的场景吗?

“我需要处理这个Task吗?”的问题。只能通过任务的消费方式来回答。特别是,请考虑博客文章中的这句话:

分配 WaitHandle 的唯一方法是您明确要求任务的 IAsyncResult.AsyncWaitHandle,这种情况应该很少见。

里德当时的回答是正确的,但延续使用的情况不再如此AsyncWaitHandle。如今,没有任何东西会AsyncWaitHandle隐式使用,所以你应该只考虑Disposeing Tasks 如果你的消费代码将任务视为 anIAsyncResult 访问AsyncWaitHandle属性。即使那样,您也应该只考虑处置它们;这不是绝对必要的。

请不要告诉我,只要你不能告诉我一个更好的方法,它与 async/await 模式非常兼容,并且能够将这些数据包分发给各种选定的侦听器,请不要告诉我这种方法是一个糟糕的选择。

我建议将异步兼容的生产者/消费者队列构建为单独的类型;我认为这将有助于您的代码更清晰。您可以使用BufferBlock<T>我的 AsyncEx 库中的异步队列类型,或者使用异步兼容的监视器构建您自己的。

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

于 2019-02-19T14:58:12.890 回答