如何理解阻塞、非阻塞与同步、异步的区别?

詹学伟
詹学伟
发布于 2024-04-27 / 2 阅读
0
0

如何理解阻塞、非阻塞与同步、异步的区别?

同步与异步

同步与异步关注的是消息通信机制

  • 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。

  • 异步则是相反,调用在发出之后,这个调用就直接返回了,所以就没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出之后,被调用者通过“状态”“通知”“回调”三种途径通知调用者。

可以使用哪一种途径依赖于被调用者的实现,除非被调用者提供多种选择,否则不受调用者控制。

  • 如果被调用者用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低。

  • 如果使用通知和回调的方式,效率则很高。因为被调用者几乎不需要做额外的操作。

举个例子:

你打电话问书店老板有没有《高效演讲》这本书。

如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。

异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

阻塞与非阻塞

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。

  • 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

  • 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

接着上面的例子:

打电话问书店老板有没有《高效演讲》这本书,

  • 如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果。

  • 如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了(先去干点别的,不用傻等), 当然你也要偶尔过几分钟检查一下老板有没有返回结果。

故事描述

百里爱喝茶。

出场人物:百里,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。

  1. 百里把水壶放到火上,立等水开,什么都不做,(同步阻塞)百里觉得自己有点傻。

  2. 百里把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)。

  3. 百里还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。

  4. 百里烧水,但站在水壶前啥也不干(线程阻塞),等水壶响了(异步回调)取水。(异步阻塞)。

  5. 百里觉得这样傻等意义不大,百里把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)。

  • 同步异步,只是对于水壶而言

  • 普通水壶,同步。

  • 响水壶,异步。

虽然都能干活,但响水壶可以在自己完工之后,提示百里水开了。这是普通水壶所不能及的。同步只能让调用者去轮询自己(情况2中),造成百里效率的低下。

  • 阻塞非阻塞,仅仅对于百里而言。

  • 立等的百里,阻塞。

  • 看电视的百里,非阻塞。

情况1和情况3中百里就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的百里没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

回调函数

前面提到,回调是异步调用的一种实现方式。那么什么是回调函数呢?

  • 概念

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

  • 举个例子

概念不是太好理解,我们举个例子。

沿用上面买书的例子,你的电话号码就叫回调函数,你把电话留给书店老板就叫登记回调函数,书店老板查好了叫做触发了回调关联的事件,老板给你打电话叫做调用回调函数。你接电话叫做响应回调事件。


评论