【问题标题】:Asynchronous operation and thread in C#C#中的异步操作和线程
【发布时间】:2015-06-03 04:52:50
【问题描述】:

异步编程是一种在后台调用长时间运行的方法以使 UI 线程保持响应的技术。它应该在调用 Web 服务或数据库查询或任何 I/O 绑定操作时使用。当异步方法完成时,它会将结果返回给主线程。这样,程序的主线程就不必等待 I/O 绑定操作的结果,而是继续执行进一步的操作,而不会阻塞/冻结 UI。没关系。

据我所知,异步方法在后台工作线程上执行。运行时使线程池中的线程可用,或者它可以创建一个全新的线程来执行它。

但我在许多帖子中读到异步操作可以在单独的线程上执行或不使用任何线程执行。现在我很困惑。

1) 您能否帮助澄清一下异步操作在什么情况下不使用线程?

2) 处理器内核在异步操作中的作用是什么?

3) 它与多线程有何不同?我知道多线程对计算绑定操作很有用。

请帮忙。

【问题讨论】:

  • C#中有多种异步方式——你是指异步编程模型(或Begin/End风格),基于事件的异步模式(完成EventHandlers),还是任务异步模式(async/await/Task 风格)?
  • 嗨,Jeffrey,在所有情况下 - APM、EAP 和 TAP。我在某处读到 EAP 使用后台线程。
  • 但是 TAP 可能使用也可能不使用线程池线程。
  • 感谢 Jeffery...您的博文对我帮助很大。谢谢。

标签: c# multithreading asynchronous


【解决方案1】:

IO(比方说网络上的数据库操作)是这三个方面的一个很好的例子:

  1. 你基本上只是注册一个回调,当 IO 操作完成时操作系统最终会调用(可能在一个新创建的线程上)。没有线程等待 - 复活将由硬件事件触发(或至少由通常在用户空间之外的操作系统进程触发)

  2. 它可能没有(见 1)

  3. 在多线程中,您使用了多个线程(您的后台线程),并且有一个可能闲置在那里什么都不做(但会耗尽系统资源) - 如果您拥有 需要计算的东西(因此线程不会空闲等待外部结果) - 使用后台工作线程是有意义的

【讨论】:

  • 您好 Carsten,您的意思是说在异步 IO 绑定操作的情况下,不会在后台线程上执行。操作系统只使用线程池线程来调用回调方法?
  • 是的,如果操作正确的话。这就是为什么 async 我说 scale
  • 好的..非常感谢您..但是在您的最后一条评论中还有一个子句..“如果正确完成”。这是什么意思?如果异步 IO 绑定操作不在线程上执行,那么它在哪里执行?在另一个操作系统进程中?如果是,那么在另一个操作系统进程中必须有专用线程?
  • 不,我不必在线程中 - 基本上,当操作系统在您的网络硬件发出新数据信号后恢复您的计算时就足够了,操作系统检查...... - 细节非常复杂,但基本上只要有硬件中断,您就不必一直观看 ;) - 如果正确完成意味着必须正确完成操作系统、框架等中的实现 - 例如 I 认为 Task.Delay 仍将使用线程/计时器,因此即使它看起来是异步的,您也不会真正获得(所有)好处
  • 非常感谢卡斯滕...你帮了我很多忙 :)
【解决方案2】:

异步操作实际上并不意味着它们是如何处理的,只是它们希望稍后将您的结果回复给您。举例:

  • 他们可能(正如您所提到的)将计算密集型任务拆分到一个独立线程上,但这不是唯一的用例。
  • 它们有时可能会在启动它们的调用中同步完成,在这种情况下不使用额外的线程。如果已经有足够的缓冲区内容(输入)或空闲缓冲区空间(输出)来为请求提供服务,则 I/O 请求可能会发生这种情况。
  • 他们可能会简单地将长时间运行的 I/O 请求发送到系统;在这种情况下,回调可能会在收到来自 I/O 完成端口的通知后发生在后台线程上。
  • 完成后,稍后可能会在同一线程上传递回调;这在 UI 框架内的事件中尤其常见,例如 WebBrowser 中的导航。

【讨论】:

    【解决方案3】:

    异步并没有说明线程。它是关于拥有某种将在“状态机”内部处理的回调(不是很正确,但你可以把它想象成事件)。异步不会引发线程,也不会显着分配系统资源。您可以运行任意数量的异步方法。

    线程确实对您的系统有真正的影响,您可以同时拥有的数量非常有限。

    Io 操作主要与其他控制器(HDD、NIC、...)有关。如果您创建一个线程,那么现在发生的情况是,您的应用程序的一个无事可做的线程等待控制器完成。在异步中,正如 Carsten 和 Jeffrey 已经提到的,您只需获得某种回调机制,以便您的线程继续执行其他工作、方法等。

    另外请记住,每个线程都会消耗资源(RAM、性能、处理垃圾收集变得更糟,...),甚至可能出现异常(OutOfMemoryException...)

    那么什么时候使用线程呢?绝对只有当你真的需要它时。如果有异步 api,除非您有非常重要的理由不使用它,否则请使用它。 在过去的日子里,异步 api 真的很痛苦,这就是为什么很多人在他们只需要异步的时候就使用线程。

    例如 node.js 完全拒绝使用多线程!

    如果您处理多个请求,例如在总是有工作要做的服务/网站中,这一点尤其重要。还有一个简短的webcast with Jeffrey Richter 关于这个帮助我理解了

    也看看这个MSDN article PS:作为副作用,带有 async 和 await 的源代码往往更具可读性

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2017-09-13
      • 2016-06-08
      • 1970-01-01
      • 2021-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多