与BeginXXX / EndXXX相比,异步的优势是什么?

时间:2015-02-23 21:59:18

标签: c# .net asynchronous network-programming async-await

在寻找从UDP套接字异步接收数据报流的优雅方式时,我遇到了这个问题:How to use asynchronous Receive for UdpClient in a loop?

我理解的第一个答案的优点,因为他们使用熟悉的BeginReceive / EndReceive方法。这个解决方案很好,因为没有任何线程被阻塞。

second answer提供了两种不同的Task-ish解决方案,一种使用ReceiveAsync,另一种使用同步Receive方法。在这种情况下,我想知道它的优点是什么。据我了解,即使在ReceiveAsync的情况下,还有一个(threadpool?)线程等待事情发生。

在这种情况下使用Async方法有优势吗?如果没有,有没有办法使用Async方法实现这种类型的模式,而没有线程,任务或其他阻塞对象的开销?

2 个答案:

答案 0 :(得分:3)

首先,在自然异步API中,async-await(TAP)版本和Begin/End(APM)(There Is No Thread)都没有阻塞线程。

但是,在这种特定情况下,链接的答案会不必要地浪费ThreadPool个帖子,应该避免这种情况。

ReceiveAsync情况将操作的同步部分(直到await ReceiveAsync)卸载到ThreadPool线程。如果您要执行实质性的CPU绑定操作并且想要释放调用线程,这将非常有用。这似乎并非如此,因为除了创建客户端之外别无其他。

您只需删除Task.Run并使用async方法:

async Task ListenAsync(int port, CancellationToken token)
{
    using (var client = new UdpClient(port))
    {
        while (true)
        {
            var result = await client.ReceiveAsync().WithCancellation(token).ConfigureAwait(false);
            // process result.Buffer
        }
    } 
}

答案 1 :(得分:0)

好吧,它分配一个线程池线程来等待异步操作完成。相反,它将线程池线程分配给启动异步操作,而不是在当前线程中启动它。

实际上没有任何理由这样做,至少除非启动异步操作的行为需要很长时间,并且如果已经正确写入它真的不应该。

如果不在线程池线程中启动异步操作,是否可以实现相同的功能,当然,只需删除代码即可在线程池线程中启动它。