【问题标题】:Asynchronous vs Multithreading - Is there a difference?异步与多线程 - 有区别吗?
【发布时间】:2010-10-10 16:34:22
【问题描述】:

异步调用是否总是创建一个新线程?两者有什么区别?

异步调用是否总是创建或使用新线程?

Wikipedia says:

在计算机编程中,异步事件是独立于主程序流发生的事件。异步动作是在非阻塞方案中执行的动作,允许主程序流继续处理。

我知道异步调用可以在单线程上完成?这怎么可能?

【问题讨论】:

  • JavaScript 没有线程,但它有异步方法调用。
  • 任何一个进程管理多个子进程的系统,控制进程可以提供子进程的异步操作。在 JavaScript 的情况下,浏览器提供计算流。当某个函数进行异步调用时,浏览器可以存储该函数的上下文。现在,同一个浏览器线程可以更改上下文以恢复另一个函数的执行。而在传统的多线程程序中,一个线程执行一个功能块以允许另一个线程运行不同的功能。每个线程同步执行自己的功能。

标签: multithreading language-agnostic asynchronous


【解决方案1】:

只要需要异步执行的操作不需要 CPU 完成工作,就可以在不产生另一个线程的情况下完成该操作。例如,如果异步操作是 I/O,则 CPU 不必等待 I/O 完成。它只需要启动操作,然后可以在 I/O 硬件(磁盘控制器、网络接口等)执行 I/O 工作时继续其他工作。硬件通过中断 CPU 让 CPU 知道何时完成,然后操作系统将事件传递给您的应用程序。

通常更高级别的抽象和 API 不会公开操作系统和底层硬件提供的底层异步 API。在这些情况下,创建线程来执行异步操作通常更容易,即使生成的线程只是在等待 I/O 操作。

如果异步操作需要 CPU 来完成工作,那么通常该操作必须在另一个线程中进行才能真正实现异步。即使这样,如果有多个执行单元,它实际上只会是异步的。

【讨论】:

  • 解释清楚,谢谢;但我有一个问题。您提到“例如,如果异步操作是 I/O,CPU 不必等待 I/O 完成。它只需要启动操作”。我的问题是当程序是单线程时,在代码第 3 行中,你调用了一个 I/O 操作,那么如何在第 3 行开始操作并执行第 4 行而不等待 I/O 操作完成?对我来说,我得把第3行的代码放到一个新线程中,实现第4行的执行,不用等待I/O操作完成。【Java pgm视角】
  • 原因是,虽然CPU不必等待,但CPU会等待I/O操作完成……我相信你的第二段是我查询的答案。在这种情况下,我需要得出结论,在 Java 中,异步调用需要在不同的线程中执行。如果我错了,请纠正我,或者让我知道我是否必须发布新的 SO qn
  • @spiderman 一些语言,比如 Node.js,有一个异步编程模型。语言和运行时提供了允许在同一个线程中执行第 4 行的内置函数,甚至在 IO 操作完成之前。这是通过第 3 行提供的回调实现的,运行时将在 IO 完成时调用该回调。
  • @spiderman 也许......操作系统的异步函数只是直接返回 false 或其他东西。
【解决方案2】:

这个问题太笼统了,无法回答。

一般情况下,异步调用不一定会创建新线程。这是实现它的一种方式,预先存在的线程池或外部进程是其他方式。它在很大程度上取决于语言、对象模型(如果有)和运行时环境。

异步只是意味着调用线程不会坐下来等待响应,异步活动也不会发生在调用线程中。

除此之外,您还需要更加具体。

【讨论】:

  • 所以我说的基本上是对的:多线程 == 使用多线程以便为处理器密集型任务提供处理优势,这些任务[理想情况下]能够从多个处理器中受益,以及在异步情况下的好处。异步 == 一个进程完成它的事情,而调用该进程的状态不必等待它完成。 (可能不一定要使用多个线程来执行此操作——即其他硬件组件可能会负责)。
  • @Michael - 你能用一个例子解释一下异步编程是如何在单线程中发生的吗?
  • @KumarVaibhav - 最常见的例子是单个线程处理队列中的项目(例如,Windows 消息队列)。如果程序习惯于将项目发送到它自己的队列中(一种常见模式),那么发送项目的代码位不会等待操作完成,而只是返回。该操作将由主循环在适当的时候处理。
  • 代码的编写方式和执行方式之间可能存在差异。例如,在 C# 中,我可以有一个启动异步任务的方法,我的方法是完全异步的,并且可以在不等待任务完成的情况下执行其他操作。但是,CLR 也可以决定内联我的任务并同步执行。
  • 哪个线程执行等待的任务?标有 a-sync 的方法是同步执行的,直到到达 await 关键字,此时哪个线程执行这个 await-able 任务?
【解决方案3】:

不,异步调用并不总是涉及线程。

他们通常会启动某种与调用者并行继续的操作。但该操作可能由另一个进程、操作系统、其他硬件(如磁盘控制器)、网络上的其他计算机或人类来处理。线程并不是并行完成任务的唯一方法。

【讨论】:

    【解决方案4】:

    JavaScript 是单线程和异步的。例如,当您使用 XmlHttpRequest 时,您为其提供了一个回调函数,该回调函数将在响应返回时异步执行。

    John Resig 很好地解释了timers work in JavaScript 的相关问题。

    【讨论】:

      【解决方案5】:

      多线程是指在同一进程中发生多个操作。而异步编程跨进程传播。例如,如果我的操作调用 Web 服务,线程不需要等到 Web 服务返回。这里我们使用异步编程,它允许线程不等待另一台机器上的进程完成。当它开始从 web 服务获得响应时,它可以中断主线程,说 web 服务已经完成了对请求的处理。现在主线程可以处理结果了。

      【讨论】:

      • 我有点不同意。我编写了一个单线程 HTTP 服务器,它使用异步 IO 完成来处理多个同时请求。异步不需要在多个执行路径中发生事情,它只是意味着多个计算流可以重叠。另一种看待它的方式是,在单线程操作系统上,我可以让 2 个进程“同时”运行。从每个进程的角度来看,它们是同步运行的。但是,从操作系统的角度来看,它是异步操作的。
      • 在找到一个承认线程和同步是两个独立概念的答案之前,我不得不滚动太多。
      【解决方案6】:

      自非抢占时代(版本 2.13、3.0、3.1 等)以来,Windows 一直使用消息循环进行异步处理,远远早于支持真正的线程。所以回答你的问题,不,不需要创建线程来执行异步处理。

      【讨论】:

      • @dmckee - 有趣的是不同的系统如何以相似的方式发展。
      【解决方案7】:

      异步调用甚至不需要与调用调用的系统/设备发生在同一系统/设备上。所以如果问题是,异步调用是否需要当前进程中的线程,答案是否定的。但是,处理异步请求的地方必须有一个执行线程。

      执行线程是一个模糊的术语。在诸如早期的 Macintosh 和 Windows 操作系统等协作任务系统中,执行线程可能只是使请求运行另一个堆栈、指令指针等的同一进程......然而,当人们通常谈论异步调用时,它们通常表示如果是进程内(即在同一进程内)则由另一个线程处理的调用,或者如果它是进程间的则由另一个进程处理。

      请注意,进程间(或进程间)通信 (IPC) 通常被概括为包括进程内通信,因为锁定和同步数据的技术通常是相同的,而不管单独的线程是什么进程执行运行。

      【讨论】:

        【解决方案8】:

        某些系统允许您利用内核中的并发性来实现某些使用回调的功能。对于一个相当模糊的实例,异步 IO 回调用于在 Mac System 6-8 的非抢占式多任务处理时代实现非阻塞互联网服务器。

        这样,您就可以在没有线程的情况下“在”您的程序中实现并发执行流

        【讨论】:

          【解决方案9】:

          异步只是意味着您不会阻塞您的程序等待某事(函数调用、设备等)完成。它可以在单独的线程中实现,但也很常见的是使用专用线程执行同步任务并通过某种事件系统进行通信,从而实现类似异步的行为。

          有单线程异步程序的例子。比如:

          ...do something
          ...send some async request
          while (not done)
              ...do something else
              ...do async check for results
          

          【讨论】:

            【解决方案10】:

            异步调用的本质是,如果您希望应用程序在调用过程中继续运行,您将需要生成一个新线程,或者至少 使用您创建的另一个线程,该线程仅用于处理异步回调。

            有时,根据具体情况,您可能希望调用异步方法,但要让用户觉得它是同步的(即阻塞,直到异步方法发出信号通知它已完成)。这可以通过WaitForSingleObject等Win32 API来实现。

            【讨论】:

            • 这在某些系统上是正确的,但不是全部。 Unix 不要求您生成或使用另一个线程,除非您将内核称为另一个线程,我想这是看待它的一种方式。
            • 在 Windows 上也不是这样。例如,重叠的 I/O 是异步的。
            猜你喜欢
            • 2016-04-13
            • 2018-12-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-10
            • 2021-01-31
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多