【问题标题】:What is the advantage of async over BeginXXX/EndXXX?与 BeginXXX/EndXXX 相比,异步有什么优势?
【发布时间】:2015-02-25 01:35:50
【问题描述】:

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

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

second answer 提供了两种不同的任务式解决方案,一种使用ReceiveAsync,另一种使用同步Receive 方法。我想知道,在这种情况下,优势是什么。据我了解,即使在 ReceiveAsync 的情况下,仍然有一个(线程池?)线程在等待事情发生。

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

【问题讨论】:

  • As I understand it, even in the ReceiveAsync case, there's still a (threadpool?) thread waiting around for things to happen. 异步的全部意义在于这不是真的。阅读blog.slaks.net/2014-12-23/parallelism-async-threading-explained
  • 特别是,*Async() 方法只是对 Begin*() 方法的更友好的包装。
  • @SLaks 查看链接的帖子;它实际上是不必要地分配线程池线程来做一些工作,虽然不像 OP 认为的那么多。
  • @Servy:这很好;他的Task.Run() 电话完全没用。
  • 您从第二个答案中得到了美好的画面。他故意不对收到的数据做任何事情,也不处理任何错误。一旦你把它充实起来,你肯定会看到不同之处。使用 APM 时,这些细节会变得非常糟糕。

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


【解决方案1】:

首先,在自然异步 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
        }
    } 
}

【讨论】:

  • 是的,在自然异步 API 中没有线程,但是在问题特别提到它不是正确实现的示例中,它确实不必要地创建了线程池线程,没有必要使用FromAsync,因为已经有一个Task返回异步方法,而且你在TPL上的cmets作为一个范式更可取,面对这个问题,它询问属性是相当离题的使用该范例的特定实现。
  • @Servy OP 询问(特别是在标题中)TAP 相对于 APM 和不同 TAP 版本的优势。这个答案涵盖了一般情况和具体情况。
  • 所以您阅读了标题而没有阅读问题的正文?问题的主体清楚地表明,它没有询问异步方法的不同方法之间的区别。
  • @Servy 我读过两者。并回答了两者。这是至关重要的,因为这篇文章将是未来谷歌搜索的最终结果。而且“即使在ReceiveAsync 的情况下,仍然有一个(线程池?)线程在等待事情发生。” 让这件事变得比你想象的要清楚得多。
  • 因此,重要的是要问一个 OP 实际上并没有问的问题,因为未来的读者可能会犯和你一样的错误,并相信 OP 提出的问题完全不同?如果有人发现一个看似相似但实际上所问的问题与他们所问的问题不同的问题,那么他们就不能真正期望得到他们问题的答案。如果有人想知道其他事情恰好发现了问题,您就无法回答所有问题。
【解决方案2】:

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

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

你可以在不启动线程池线程的异步操作的情况下实现同样的事情吗,当然,只需删除代码以在线程池线程中启动它。

【讨论】:

    猜你喜欢
    • 2016-07-04
    • 2011-03-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 2018-06-09
    • 2010-09-24
    • 2010-12-27
    相关资源
    最近更新 更多