在寻找从UDP套接字异步接收数据报流的优雅方式时,我遇到了这个问题:How to use asynchronous Receive for UdpClient in a loop?
我理解的第一个答案的优点,因为他们使用熟悉的BeginReceive
/ EndReceive
方法。这个解决方案很好,因为没有任何线程被阻塞。
second answer提供了两种不同的Task-ish解决方案,一种使用ReceiveAsync
,另一种使用同步Receive
方法。在这种情况下,我想知道它的优点是什么。据我了解,即使在ReceiveAsync
的情况下,还有一个(threadpool?)线程等待事情发生。
在这种情况下使用Async方法有优势吗?如果没有,有没有办法使用Async方法实现这种类型的模式,而没有线程,任务或其他阻塞对象的开销?
答案 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)
好吧,它不分配一个线程池线程来等待异步操作完成。相反,它将线程池线程分配给启动异步操作,而不是在当前线程中启动它。
实际上没有任何理由这样做,至少除非启动异步操作的行为需要很长时间,并且如果已经正确写入它真的不应该。
如果不在线程池线程中启动异步操作,是否可以实现相同的功能,当然,只需删除代码即可在线程池线程中启动它。