ChatGPT解决这个技术问题 Extra ChatGPT

异步和非阻塞调用?也在阻塞和同步之间

异步调用和非阻塞调用有什么区别?还在阻塞和同步调用之间(请提供示例)?

在阅读 Col 1, Chapter 6 一书时,我对这些差异有了很好的理解。
一篇有趣的文章:Boost application performance using asynchronous I/O。它将 I/O 范例分为 4 类:(1) 阻塞 + 同步,(2) 非阻塞 + 同步,(3) 阻塞 + 异步,以及 (4) 非阻塞 + 异步。
@MSDousti 有人告诉我,谷歌专家告诉我这在某些方面是错误的。
@MSDousti 经过一番研究,我认为没有您在评论中描述的组合(3)和(2)。检查异步的定义,它与非阻塞相同。正如您所看到的最佳答案,它证实了我的观点。轮询和回调函数仅仅是实现异步的方式/模式。是的,我是说阻塞、同步和非阻塞、异步是 2 对同义词。

D
Dexter

在许多情况下,它们是同一事物的不同名称,但在某些情况下,它们是完全不同的。所以这取决于。术语在整个软件行业中的应用方式并不完全一致。

例如,在经典的套接字 API 中,非阻塞套接字是简单地立即返回并带有特殊的“将阻塞”错误消息的套接字,而阻塞套接字会阻塞。您必须使用单独的函数(例如 selectpoll)来确定何时是重试的好时机。

但是异步套接字(由 Windows 套接字支持)或 .NET 中使用的异步 IO 模式更方便。你调用一个方法来启动一个操作,当它完成时框架会回调你。即使在这里,也有基本的区别。异步 Win32 套接字通过传递 Window 消息将其结果“编组”到特定的 GUI 线程,而 .NET 异步 IO 是自由线程的(您不知道回调将在哪个线程上调用)。

所以他们并不总是意味着同样的事情。为了提炼套接字示例,我们可以说:

阻塞和同步的意思是一样的:你调用 API,它会挂起线程,直到它得到某种答案并将它返回给你。

非阻塞意味着如果无法快速返回答案,API 会立即返回错误并不执行任何其他操作。所以必须有一些相关的方法来查询API是否准备好被调用(即以一种有效的方式模拟等待,避免在紧密循环中手动轮询)。

异步意味着 API 总是立即返回,已经开始“后台”工作来满足您的请求,因此必须有一些相关的方式来获取结果。


就绪状态 IO 而不是完成状态 IO;在 Linux 上参见 libaio
感谢您指出这些术语是上下文相关的,有时可能会不一致地使用。我发现,尤其是在技术领域,但在其他领域,承认这一事实往往比就哪个精确定义是正确的争论更有用,有时会发生这种情况。
跟进问:答案似乎对这些术语进行了两种不同的区分。首先,通知:非阻塞意味着应用程序必须稍后再次检查(轮询),而异步意味着我们可以忘记它并依靠框架/操作系统通过回调或发布事件来通知我们。其次,动作:非阻塞只会返回错误,而异步将动作排队或在某种意义上“在后台”执行。在区分术语时,哪个区别更重要?任一区别是否与一个术语的相关性更强?还是模棱两可?
@ChadNB - 作为术语,非阻塞与轮询密切相关。关于 API 是否“记住”您尝试调用它的问题:API 记住的唯一原因是为了给您回电。如果您要调用它来重新轮询,那么您已经必须维护必要的状态才能知道进行后续调用,因此 API 不会通过维护状态来增加任何价值。
与其说非阻塞调用返回一个“错误”,我认为更准确地说,非阻塞调用基本上可以立即完成,然后指出它做了多少。对于某些操作,完成的工作量将是“所有”或“无”,但其他一些操作(如流 I/O)可能会返回定量指示。如果阻塞 I/O 实现允许超时的操作在以后顺利重试(有些可以;有些不可以),则非阻塞在语义上等同于具有非常短的超时的阻塞。
Y
Yves

同步/异步是描述两个模块之间的关系。阻塞/非阻塞是描述一个模块的情况。

示例:模块 X:“I”。模块 Y:“书店”。 X问Y:你有一本叫《c++入门》的书吗?

阻塞:在 Y 回答 X 之前,X 一直在那里等待答案。现在 X(一个模块)正在阻塞。 X和Y是两个线程还是两个进程还是一个线程还是一个进程?我们不知道。非阻塞:在 Y 回答 X 之前,X 只是离开那里做其他事情。 X 可能每两分钟回来检查 Y 是否完成了它的工作?或者 X 不会回来,直到 Y 给他打电话?我们不知道。我们只知道在 Y 完成它的工作之前 X 可以做其他事情。这里 X(一个模块)是非阻塞的。 X和Y是两个线程还是两个进程还是一个进程?我们不知道。但我们确信 X 和 Y 不可能是一个线程。同步:在 Y 回答 X 之前,X 一直在那里等待答案。这意味着 X 不能继续,直到 Y 完成它的工作。现在我们说:X 和 Y(两个模块)是同步的。 X和Y是两个线程还是两个进程还是一个线程还是一个进程?我们不知道。异步:在 Y 回答 X 之前,X 离开那里,X 可以做其他工作。 X 不会回来,直到 Y 给他打电话。现在我们说:X 和 Y(两个模块)是异步的。 X和Y是两个线程还是两个进程还是一个进程?我们不知道。但我们确信 X 和 Y 不可能是一个线程。

请注意上面的两个粗体句子。为什么 2) 中的粗体句子包含两种情况,而 4) 中的粗体句子仅包含一种情况?这是非阻塞和异步之间区别的关键。

让我试着用另一种方式来解释这四个词:

阻塞:天哪,我被冻结了!我动不了!我必须等待那个特定的事件发生。如果发生这种情况,我会得救的!非阻塞:有人告诉我必须等待特定事件发生。好的,我明白了,我保证我会等的。但是在等待的时候,我还可以做一些其他的事情,我没有被冻住,我还活着,我会跳,我会走路,我会唱歌等同步:我妈妈要做饭,她送我买点肉。我只是对妈妈说:我们是同步的!很抱歉,即使我可能需要 100 年才能找回一些肉,您也必须等待……异步:我们将制作比萨饼,我们需要番茄和奶酪。现在我说:我们去购物吧。我买些西红柿,你买些奶酪。我们不需要互相等待,因为我们是异步的。

这是一个关于非阻塞和同步的典型示例:

// thread X
while (true)
{
    msg = recv(Y, NON_BLOCKING_FLAG);
    if (msg is not empty)
    {
        break;
    }
    else
    {
        sleep(2000); // 2 sec
    }
}

// thread Y
// prepare the book for X
send(X, book);

你可以看到这个设计是非阻塞的(你可以说这个循环大部分时间都在做一些无意义的事情,但在 CPU 的眼中,X 正在运行,这意味着 X 是非阻塞的。如果你愿意,你可以替换 sleep(2000)与任何其他代码),而 X 和 Y(两个模块)是同步的,因为 X 不能继续做任何其他事情(X 不能跳出循环),直到它从Y.
通常在这种情况下,使 X 阻塞要好得多,因为非阻塞会为愚蠢的循环花费大量资源。但是这个例子很好地帮助你理解了一个事实:非阻塞并不意味着异步。

这四个词确实很容易让我们混淆,我们应该记住的是,这四个词是为建筑设计服务的。了解如何设计一个好的架构是区分它们的唯一方法。

例如,我们可以设计这样一种架构:

// Module X = Module X1 + Module X2
// Module X1
while (true)
{
    msg = recv(many_other_modules, NON_BLOCKING_FLAG);
    if (msg is not null)
    {
        if (msg == "done")
        {
            break;
        }
        // create a thread to process msg
    }
    else
    {
        sleep(2000); // 2 sec
    }
}
// Module X2
broadcast("I got the book from Y");


// Module Y
// prepare the book for X
send(X, book);

在这里的例子中,我们可以说

X1 是非阻塞的

X1 和 X2 是同步的

和 Y 是异步的

如果需要,也可以用这四个字来描述在 X1 中创建的那些线程。

再来一次:这四个字是为建筑设计服务的。所以我们需要的是做一个合适的架构,而不是像语言律师那样区分四个词。如果你遇到一些情况,你不能很清楚地区分这四个词,你应该忘记这四个词,用你自己的话来描述你的架构。

所以更重要的是:我们什么时候使用同步而不是异步?我们什么时候使用阻塞而不是非阻塞?使 X1 阻塞比非阻塞更好吗?使 X 和 Y 同步比异步更好吗?为什么 Nginx 是非阻塞的?为什么 Apache 会阻塞?这些问题是你必须弄清楚的。

要做出好的选择,您必须分析您的需求并测试不同架构的性能。没有适合各种需求的架构。


IMO 是最佳答案,因为它抓住了概念的本质:一两个参与者之间的关系。
在 1 和 3 中,Y 都充当有限资源。没有更多的 Y 可以帮助 X
那么这是否意味着阻塞和同步都是一样的呢?更像动词和名词形式的区别?
@VineethChitteti 你最好不要那样说。 X 和 Y 可以同步,而 X 没有阻塞。
N
Nikolai Fetissov

异步是指并行完成的事情,比如另一个线程。

非阻塞通常指轮询,即检查给定条件是否成立(套接字可读,设备有更多数据等)


当涉及 I/O 时,异步通常不是“并行”,也不是“另一个线程”,主要是基于通知的。即:不阻塞,不轮询,只获取信号。当然,可以说信号来自“现实世界”,可以被认为是“另一个线程”......
好吧,是的,我们可以整天争论确切的措辞:)
但是你如何解释 Linux 中的 AIO?它同时使用了异步和非阻塞。 AIO LINKS
对于阅读此答案的任何人:这并不是在争论确切的措辞。同样,并发性和并行性不是同一个概念,区分它们不是措辞问题。异步性和并行性是两种不同的野兽,这个答案不准确地使它们变得相同。
异步并不一定意味着它是并行完成的,请参阅 stackoverflow 上关于并发和并行编程的这篇很棒的post
D
Didier A.

同步被定义为同时发生(以可预测的时间或可预测的顺序)。

异步被定义为不同时发生。 (具有不可预测的时间或不可预测的顺序)。

这是导致第一个混淆的原因,即异步是某种同步方案,是的,它的意思是,但实际上它描述了关于它们运行的时间或顺序不可预测地发生的进程。并且此类事件通常需要同步才能使它们正常运行,在存在多种同步方案的情况下,其中一种称为阻塞,另一种称为非阻塞,还有一种令人困惑地称为异步。

所以你看,整个问题在于找到一种同步异步行为的方法,因为你有一些操作需要另一个操作才能开始。因此这是一个协调问题,你怎么知道你现在可以开始那个操作了?

最简单的解决方案称为阻塞。

阻塞是当您选择等待其他事情完成并在继续进行需要它的操作之前向您返回响应时。

因此,如果您需要在吐司上涂上黄油,那么您首先需要烤面包。你协调它们的方式是,你首先烤面包,然后无休止地盯着烤面包机,直到它弹出烤面包,然后你继续在它们上面涂黄油。

这是最简单的解决方案,效果很好。没有真正的理由不使用它,除非您碰巧还有其他不需要与操作协调的事情要做。例如,做一些菜。既然你知道这需要一点时间,而且你可以在它完成的时候洗一整盘菜,为什么还要一直盯着烤面包机等着烤面包呢?

这就是分别称为非阻塞和异步的另外两种解决方案发挥作用的地方。

非阻塞是当你在等待操作完成时选择做其他不相关的事情。在您认为合适的情况下检查响应的可用性。

所以不要看着烤面包机让它弹出。你去洗一整盘菜。然后你偷看烤面包机,看看烤面包是否爆了。如果他们没有,你去洗另一道菜,在每道菜之间检查烤面包机。当你看到吐司爆开时,你停止洗盘子,取而代之的是你拿起吐司继续往上面抹黄油。

不得不经常检查烤面包可能很烦人,想象一下烤面包机在另一个房间里。在两道菜之间,你浪费时间去另一个房间检查吐司。

异步来了。

异步是当您等待操作完成时选择做其他不相关的事情。但是,您不是检查它,而是将检查工作委托给其他东西,可能是操作本身或观察者,并且当响应可用时,您会通知该事物并可能中断您,以便您可以继续进行其他操作需要它。

这是一个奇怪的术语。没有多大意义,因为所有这些解决方案都是创建依赖任务的同步协调的方法。这就是为什么我更喜欢称它为事件。

所以对于这个,你决定升级你的烤面包机,这样当烤面包完成时它会发出哔哔声。你碰巧一直在听,即使你在洗碗。听到哔哔声时,你会在记忆中排队,一旦你洗完当前的盘子,你就会停下来把黄油放在吐司上。或者您可以选择中断当前盘子的洗涤,并立即处理吐司。

如果您无法听到哔哔声,您可以让您的伴侣为您看烤面包机,并在烤面包准备好时告诉您。您的伴侣可以自己选择上述三种策略中的任何一种来协调其观察烤面包机并告诉您何时准备就绪的任务。

最后要注意的是,虽然非阻塞和异步(或者我更喜欢称之为事件)确实允许您在等待时做其他事情,但您并没有这样做。您可以选择不断循环检查非阻塞呼叫的状态,不做任何其他事情。这通常比阻塞更糟糕(比如看着烤面包机,然后离开,然后再看它直到它完成),所以很多非阻塞 API 允许你从它转换到阻塞模式。对于事件,您可以等待空闲,直到收到通知。这种情况下的缺点是添加通知很复杂,而且一开始可能成本高昂。您必须购买具有哔声功能的新烤面包机,或者说服您的伴侣为您观看。

还有一件事,你需要意识到这三者提供的权衡。一个并不明显比其他的好。想想我的例子。如果您的烤面包机速度如此之快,您将没有时间洗盘子,甚至没有开始洗盘子,这就是您的烤面包机的速度。在这种情况下开始做其他事情只是浪费时间和精力。阻塞就可以了。同样,如果洗盘子需要比烘烤时间长 10 倍的时间。你必须问自己什么更重要才能完成?到时候吐司可能会变冷变硬,不值得,堵也行。或者你应该在等待的时候选择更快的事情去做。还有更明显的,但我的答案已经很长了,我的观点是你需要考虑所有这些,以及实现每个的复杂性以确定它是否值得,以及它是否真的会提高你的吞吐量或性能。

编辑:

虽然已经很长了,但我也想让它完整,所以我再补充两点。

通常还存在称为多路复用的第四种模型。这是当你等待一个任务时,你开始另一个任务,当你等待两个任务时,你又开始一个,依此类推,直到你有许多任务都开始了,然后,你等待空闲,但在所有他们。因此,一旦完成任何操作,您就可以继续处理其响应,然后返回等待其他响应。它被称为多路复用,因为在您等待时,您需要一个接一个地检查每个任务,看看它们是否已完成,ad vitam,直到有一个完成。它是正常非阻塞之上的一个扩展。

在我们的示例中,这就像启动烤面包机,然后是洗碗机,然后是微波炉等。然后等待其中任何一个。你在哪里检查烤面包机看它是否完成,如果没有,你会检查洗碗机,如果没有,微波炉,然后再检查一次。

尽管我认为这是一个很大的错误,但同步通常用于一次表示一件事。一次异步很多东西。因此,您将看到用于指代阻塞和非阻塞的同步阻塞和非阻塞。而异步阻塞和非阻塞用来指多路复用和事件。

我真的不明白我们是怎么到那里的。但是当谈到 IO 和 Computation 时,同步和异步通常指的是更为人所知的非重叠和重叠。也就是说,异步意味着 IO 和计算是重叠的,也就是同时发生。虽然同步意味着它们不是,因此是顺序发生的。对于同步非阻塞,这意味着您不会启动其他 IO 或计算,您只是忙于等待并模拟阻塞调用。我希望人们停止像那样滥用同步和异步。所以我不鼓励它。

编辑2:

我想很多人对我对同步和异步的定义感到有些困惑。让我试着更清楚一点。

同步被定义为以可预测的时间和/或顺序发生。这意味着您知道某事何时开始和结束。

异步被定义为不以可预测的时间和/或顺序发生。这意味着你不知道什么时候开始和结束。

这两者可以并行或同时发生,也可以顺序发生。但是在同步情况下,您确切知道事情何时发生,而在异步情况下,您不确定事情何时发生,但您仍然可以进行一些协调,至少保证某些事情只会在其他事情发生之后发生已经发生(通过同步它的某些部分)。

因此,当您有异步进程时,异步编程允许您放置一些顺序保证,以便某些事情以正确的顺序发生,即使您不知道事情何时开始和结束。

这是一个例子,如果我们需要做 A 那么 B 和 C 可以随时发生。在顺序但异步的模型中,您可以拥有:

A -> B -> C
or
A -> C -> B
or
C -> A -> B

每次运行该程序时,您都可能会得到一个不同的,看似随机的。现在这仍然是顺序的,没有什么是并行或并发的,但是你不知道事情什么时候开始和结束,除非你已经做到了,所以 B 总是在 A 之后发生。

如果您只添加并发(无并行),您还可以获得如下内容:

A<start> -> C<start> -> A<end>   -> C<end>   -> B<start> -> B<end>
or
C<start> -> A<start> -> C<end>   -> A<end>   -> B<start> -> B<end>
or
A<start> -> A<end>   -> B<start> -> C<start> -> B<end>   -> C<end>
etc...

再一次,你真的不知道事情什么时候开始和结束,但你已经做到了,所以 B 被协调总是在 A 结束后开始,但这不一定是在 A 结束后立即开始,而是在 A 结束后的某个未知时间,和 B 可能完全或部分发生在两者之间。

如果您添加并行性,现在您将拥有以下内容:

A<start> -> A<end>   -> B<start>       -> B<end>         ->
            C<start> -> C<keeps going> -> C<keeps going> -> C<end>
or
A<start> -> A<end>         -> B<start> -> B<end>
C<start> -> C<keeps going> -> C<end>
etc...

现在,如果我们看一下同步情况,在顺序设置中,您将拥有:

A -> B -> C

这是始终的顺序,每次运行程序时,您会得到 A,然后是 B,然后是 C,即使从概念上来说 C 可以随时发生,但在同步模型中,您仍然可以准确定义它何时开始和结束.当然,您可以像这样指定它:

C -> A -> B

相反,但由于它是同步的,所以这个顺序将是每次运行程序时的顺序,除非您再次更改代码以显式更改顺序。

现在,如果您将并发添加到同步模型中,您可以获得:

C<start> -> A<start> -> C<end> -> A<end> -> B<start> -> B<end>

再一次,无论您运行程序多少次,这都是顺序。同样,您可以在代码中显式更改它,但它会在程序执行期间保持一致。

最后,如果您将并行性也添加到同步模型中,您会得到:

A<start> -> A<end> -> B<start> -> B<end>
C<start> -> C<end>

再一次,每个程序运行都会出现这种情况。这里的一个重要方面是,要以这种方式使其完全同步,这意味着 B 必须在 A 和 C 都结束后开始。如果 C 是一个可以更快或更慢地完成的操作,例如取决于机器的 CPU 功率或其他性能考虑,要使其同步,您仍然需要使其 B 等待它结束,否则您会得到异步行为同样,并非所有时间都是确定性的。

在协调 CPU 操作与 CPU 时钟时,你会得到很多这种同步的东西,你必须确保你能在下一个时钟周期内及时完成每个操作,否则你需要将所有的事情再延迟一个时钟给这个完成的空间,如果你不这样做,你会弄乱你的同步行为,如果事情依赖于那个顺序,它们就会中断。

最后,许多系统混合了同步和异步行为,所以如果您有任何类型的固有不可预测的事件,例如用户何时单击按钮,或远程 API 何时返回响应,但您需要有保证的事情排序,您基本上需要一种方法来同步异步行为,以便根据需要保证顺序和时间。一些同步策略是我之前谈到的,你有阻塞、非阻塞、异步、多路复用等。参见“异步”的重点,这就是我所说的混淆这个词的意思。有人决定将同步异步进程的策略称为“异步”。这然后错误地使人们认为异步意味着并发,同步意味着顺序,或者以某种方式阻塞与异步相反,正如我刚刚解释的那样,实际上同步和异步是一个不同的概念,与事物的时序有关同步(彼此及时,在某个共享时钟上或以可预测的顺序)或不同步(不在某个共享时钟上或以不可预测的顺序)。异步编程是一种同步两个本身异步的事件(发生在不可预测的时间和/或顺序)的策略,为此我们需要添加一些保证它们何时可能发生或至少以什么顺序发生。

所以我们剩下两件事在其中使用“异步”这个词:

异步进程:我们不知道它们将在什么时间开始和结束的进程,因此它们最终会以什么顺序运行。异步编程:一种编程风格,让您可以使用回调或观察者来同步两个异步进程,这些回调或观察者会中断执行程序,以便让他们知道某事已完成,以便您可以在进程之间添加可预测的顺序。


不知道你为什么说“同步被定义为同时发生。”?整个想法是它不是并发的,也就是不会同时发生。
这是一个很好的类比!你刚刚烤了它!
@Helsing 这就是这个词的字面意思。同步表示同一时间,异步表示不同时间:p。某些事情之所以异步,是因为它不能同时发生,它必须发生在之前或之后。如果它可以同时发生,您可以简单地并行化它,或者以任何顺序执行它,并且您不需要显式同步。这就是为什么异步编程就是做这个,然后那个,等待这些事情,然后等等。因为这些事情不可能同时发生。
@Helsing另外,并发与并行不同。这并不意味着两件事同时发生,它只意味着在任何一件事情完成之前取得了不止一件事情的进展。这可以通过并行化或简单的交错来完成,也就是任务切换。
有史以来最好的比喻!谁知道,一个简单的吐司就可以解决一个不清楚的问题。杰出的。谢谢!
K
Koray Tugay

非阻塞调用会立即返回任何可用数据:请求的全部字节数、更少或根本没有。

异步调用请求将在其整体(整体)中执行但将在未来某个时间完成的传输。


W
Wladimir Palant

将这个问题放在 java 7 中的 NIO 和 NIO.2 的上下文中,异步 IO 比非阻塞更高级。对于 java NIO 非阻塞调用,可以通过调用 AbstractSelectableChannel.configureBlocking(false) 来设置所有通道(SocketChannel、ServerSocketChannel、FileChannel 等)。但是,在这些 IO 调用返回后,您可能仍需要控制检查,例如是否以及何时再次读/写等。
例如,

while (!isDataEnough()) {
    socketchannel.read(inputBuffer);
    // do something else and then read again
}

使用 java 7 中的异步 api,这些控件可以以更通用的方式进行。两种方法之一是使用 CompletionHandler。请注意,两个 read 调用都是非阻塞的。

asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */, 
    new CompletionHandler<Integer, Object>() {
        public void completed(Integer result, Object attachment) {...}  
        public void failed(Throwable e, Object attachment) {...}
    }
}

FileChannel 不可选择且无法配置为非阻塞。
M
Mac

正如您可能从众多不同(并且通常是相互排斥的)答案中看到的那样,这取决于您问谁。在某些领域,这些术语是同义词。或者它们可能各自引用两个相似的概念:

一种解释是,调用将在后台做一些基本上不受监督的事情,以使程序不会被它不需要控制的冗长过程所阻碍。播放音频可能是一个例子——一个程序可以调用一个函数来播放(比如说)一个 mp3,从那时起可以继续做其他事情,同时让操作系统来管理在声音硬件上渲染音频的过程.

另一种解释是调用将执行程序需要监视的某些操作,但将允许大多数进程在后台发生,仅在进程的关键点通知程序。例如,异步文件 IO 可能就是一个例子——程序向操作系统提供一个缓冲区来写入文件,而操作系统仅在操作完成或发生错误时通知程序。

在任何一种情况下,目的都是让程序不会被阻塞等待缓慢的进程完成 - 程序预期如何响应是唯一真正的区别。哪个术语指的是哪个也从程序员到程序员,语言到语言,或平台到平台。或者这些术语可能指的是完全不同的概念(例如与线程编程相关的同步/异步的使用)。

对不起,但我不相信有一个全球正确的正确答案。


+1 好答案。人们需要意识到“异步”可能意味着非阻塞或 Microsoft 异步(基于事件/回调)方法。
B
Babken Vardanyan

阻塞调用:控制仅在调用完成时返回。

非阻塞调用:控制立即返回。后来操作系统以某种方式通知该调用已完成的进程。

同步程序:使用阻塞调用的程序。为了在调用期间不冻结,它必须有 2 个或更多线程(这就是为什么它被称为同步 - 线程同步运行)。

异步程序:使用非阻塞调用的程序。它只能有 1 个线程并且仍然保持交互。


非阻塞调用:控制在尽可能多地完成后立即返回;该方法表明做了多少。这与异步调用不同,异步调用的行为与您对阻塞调用的描述相同。
F
Frank Schwieterman

非阻塞:此函数在堆栈上时不会等待。

异步:在调用离开堆栈后,可以代表函数调用继续工作


@Marenz 意味着您不能直接使用 posix 调用进行非阻塞 io。这并没有改变他在这里给出的含义。
@Marenz这仅意味着文件忽略该标志。它不影响此答案的含义。
K
KJ Sudarshan

同步意味着在另一个结果之后按顺序开始。

异步意味着一起开始,结果不保证顺序

阻塞是指导致阻碍执行下一步的事情。

非阻塞意味着不等待任何东西而继续运行的东西,克服障碍物。

阻止 例如:我敲门,等他们开门。 (我在这里闲着)

非阻塞 例如:我敲门,如果他们立即打开,我会向他们打招呼,走进去等。如果他们没有立即打开,我会去隔壁家敲门。 (我在做某事或其他,不是闲着)

同步例如:只有下雨我才会出去。 (存在依赖)

异步 例如:我会出去。会下雨。 (独立事件,无论何时发生)

同步或异步,都可以是阻塞或非阻塞,反之亦然


P
P.Gurung

阻塞模型要求启动应用程序在 I/O 启动时阻塞。这意味着不可能同时重叠处理和 I/O。同步非阻塞模型允许处理和 I/O 重叠,但它要求应用程序定期检查 I/O 的状态。这留下了异步非阻塞 I/O,它允许处理和 I/O 重叠,包括 I/O 完成通知。


R
Rafique Mohammed

简单地说,

function sum(a,b){
return a+b;
}

是非阻塞的。而异步用于执行阻塞任务,然后返回其响应


s
stonemetal

它们仅在拼写上有所不同。它们所指的内容没有区别。从技术上讲,您可以说它们的重点不同。非阻塞是指控制流(它不会阻塞。)异步是指处理事件\数据时(不是同步的。)


M
Marcus

阻塞:在原语(同步或异步)处理完成后,控制返回调用进程

非阻塞:调用后控制立即返回进程


这甚至没有回答所问的问题。