异步与非阻塞

时间:2010-04-12 21:12:24

标签: asynchronous blocking synchronous

异步和非阻塞呼叫之间有什么区别?在阻塞和同步调用之间(请举例说明)?

14 个答案:

答案 0 :(得分:272)

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

例如,在经典套接字API中,非阻塞套接字是一个只是立即返回一个特殊的“会阻塞”错误消息,而阻塞套接字会被阻塞。您必须使用单独的功能,例如selectpoll来确定何时是重试的好时机。

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

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

  • 阻止和同步意味着同样的事情:你调用API,它挂起线程,直到它有某种答案并将它返回给你。
  • 非阻塞意味着如果无法快速返回答案,则API会立即返回错误并且不执行任何其他操作。因此必须有一些相关的方法来查询API是否已准备好被调用(即,以有效的方式模拟等待,以避免在紧密循环中手动轮询)。
  • 异步意味着API总是立即返回,已经开始“后台”努力来完成您的请求,因此必须有一些相关的方法来获得结果。

答案 1 :(得分:45)

  • 异步是指完成并行的事情,比如是另一个线程。
  • 非阻止通常是指轮询,即检查给定条件是否成立(套接字是否可读,设备是否有更多数据等)

答案 2 :(得分:31)

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

一个例子:
模块X:“我”。
模块Y:“书店”。
X问Y:你有一本名为“c ++ primer”的书吗?

1)阻塞:在Y回答X之前,X一直在那里等待答案。现在X(一个模块)正在阻塞。 X和Y是两个线程还是两个进程或一个线程或一个进程?我们不知道。

2)非阻塞:在Y回答X之前,X离开那里并做其他事情。 X可能每两分钟回来检查一下Y是否完成了工作?或者在Y打电话给他之前X不会回来?我们不知道。我们只知道在Y完成工作之前X可以做其他事情。这里X(一个模块)是非阻塞的。 X和Y是两个线程还是两个进程或一个进程?我们不知道。但我们确信X和Y不能是一个线程。

3)同步:在Y回答X之前,X一直在那里等待答案。这意味着在Y完成工作之前,X无法继续。现在我们说:X和Y(两个模块)是同步的。 X和Y是两个线程还是两个进程或一个线程或一个进程?我们不知道。

4)异步:在Y回答X之前,X离开那里,X可以做其他工作。 在Y打电话给他之前X不会回来。现在我们说:X和Y(两个模块)是异步的。 X和Y是两个线程还是两个进程或一个进程?我们不知道。但我们确信X和Y不能是一个线程。


请注意上面的两个粗体句子。为什么2)中的粗体句子包含两个案例而4)中的粗体句子只包含一个案例?这是非阻塞和异步之间差异的关键。

这是一个关于非阻塞& amp;典型的例子。同步:

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

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

你可以看到这个设计是非阻塞的(你可以说这个循环的大部分时间都是无意义的,但是在CPU眼中,X正在运行,这意味着X是非阻塞的)而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
    }
    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是同步的
  • X和Y是异步的

如果需要,您还可以使用四个单词描述在X1中创建的线程。

更重要的是:我们何时使用同步而不是异步?我们什么时候使用阻止而不是非阻塞?

为什么Nginx不阻塞?为什么Apache阻止?

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

答案 3 :(得分:15)

正如您可以从众多不同(通常是相互排斥的)答案中看到的那样,这取决于您的要求。在某些领域,这些术语是同义词。或者他们每个人都可以提到两个相似的概念:

  • 一种解释是,呼叫将在后台执行基本上无人监督的操作,以便允许程序不被它不需要控制的冗长过程所阻碍。播放音频可能就是一个例子 - 一个程序可以调用一个函数来播放(比方说)一个mp3,从那时起就可以继续使用其他东西,同时将它留给操作系统来管理在声音硬件上渲染音频的过程
  • 另一种解释是,调用将执行程序需要监视的某些操作,但允许大部分进程在后台进行,仅在过程中的关键点通知程序。例如,异步文件IO可能是一个示例 - 程序向操作系统提供缓冲区以写入文件,操作系统仅在操作完成或发生错误时通知程序。

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

很抱歉,但我认为没有一个正确答案是全球真实的。

答案 4 :(得分:15)

将此问题放在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) {...}
    }
}

答案 5 :(得分:12)

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

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

答案 6 :(得分:9)

非阻塞:此功能不会在堆栈上等待。

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

答案 7 :(得分:4)

同步定义为同时发生。

异步定义为不会同时发生。

这是导致第一次混乱的原因。同步实际上就是所谓的并行。虽然异步是顺序的,但请执行此操作,然后执行此操作。

现在整个问题是关于异步行为的建模,因为你有一些操作需要另一个操作才能开始。因此,它是一个协调问题,你怎么知道你现在可以开始这个操作了?

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

阻止是指您只是选择等待其他事情完成并返回响应,然后再继续执行需要它的操作。

所以,如果你需要把黄油放在烤面包上,那么你首先需要烤好的。你协调它们的方式是你先给烤好的烤面包,然后无边无际地盯着烤面包机,直到它出现在烤面包上,然后你继续把黄油涂在它们上面。

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

其他两个分别称为非阻塞和异步的解决方案正在发挥作用。

非阻止是指您在等待操作完成时选择执行其他无关的操作。根据需要检查响应的可用性。

因此,不要看着烤面包机,而不是它。你去洗一整碟。然后你偷看烤面包机,看看吐司是否爆裂了。如果他们没有,你去洗另一道菜,检查每道菜之间的烤面包机。当你看到吐司已经弹出时,你就不再洗碗了,而是拿起烤面包然后继续把黄油涂在上面。

不得不经常检查祝酒词,但是想象烤面包机在另一个房间。在菜肴之间,你浪费时间去另一个房间检查烤面包。

这是异步的。

异步是指您在等待操作完成时选择执行其他无关的操作。不是检查它,而是将检查的工作委托给其他人,可能是操作本身或观察者,并且当事件响应可用时,您可以通知并可能中断您,这样您就可以继续进行其他操作了需要它。

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

所以对于这个,你决定升级你的烤面包机,这样当吐司完成时它会发出哔哔声。即使你正在做菜,你也会不断地倾听。听到哔哔声后,你会在记忆中排队,一旦你洗完了现有的菜,你就会停下来,把黄油放在烤面包上。或者你可以选择中断当前菜肴的洗涤,并立即处理吐司。

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

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

还有一件事,你需要实现三者提供的权衡。一个人显然不比其他人好。想想我的榜样。如果您的烤面包机速度如此之快,您就没有时间洗碗,甚至没有开始洗碗,那烤箱的速度有多快。在这种情况下开始使用其他东西只是浪费时间和精力。阻止就行了。同样,如果洗碗的时间比烘烤的时间长10倍。你必须问自己,完成什么更重要?到那时候吐司可能会变冷和变硬,不值得,阻挡也会这样。或者你应该在等待时选择更快的事情。更明显的是,但我的答案已经很长了,我的观点是你需要考虑所有这一切,以及实施每一个的复杂性来决定它是否值得,以及它是否真的会改善你的整个或表演。

修改

即使这已经很久了,我也希望它完整,所以我还要再增加两点。

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

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

2)尽管我认为这是一个很大的错误,但同步通常被用来表示一次一件事。并且一次异步很多东西。因此,您会看到用于引用阻塞和非阻塞的同步阻塞和非阻塞。异步阻塞和非阻塞用于引用多路复用和偶数。

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

答案 8 :(得分:2)

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

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


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

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

答案 9 :(得分:2)

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

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

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

非阻塞意味着无需等待任何东西就可以继续运行,克服 障碍。 >

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

非阻塞例如:我敲门,如果他们立即开门,我会向他们打招呼,然后进去等等。如果他们没有立即开门,我会去下一个房子敲它。 (我在做某事,不是闲着)

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

异步例如:我会出去。可能会下雨。 (独立事件,它们何时发生无关紧要)

同步或异步,均可阻塞或非阻塞,反之亦然

答案 10 :(得分:0)

他们的拼写不同。他们提到的内容没有区别。要说技术,你可以说他们的重点不同。非阻塞是指控制流(它不会阻塞。)异步是指处理事件\数据时(不同步)。

答案 11 :(得分:0)

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

答案 12 :(得分:0)

简单地说,

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

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

答案 13 :(得分:-2)

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

非阻止:控件在调用后立即返回进程