混乱的名词

曾几何时,我只知有锁,不知有同步。接着互联网兴起,人们开始说异步。当今有一种怪象,销售也席地而坐给人讲技术。我过某传销者说“异步防阻塞”,还就何种“防”法长篇大论 ಠ_ಠ

歧义?

我初入门是学Linux和C。Java那种Synchronized,在我的认知下就是Mutex。后来听说有同步IO和异步IO。看过《UNP》之后,我理解的同步就有了两种含义(也就是说“同步”一词有歧义),当时网络上大多评论也赞同这种观点。但是后来学习了各种技术,知识,我发现自己的观点完全错了。

含糊的例子

网上流传很多解释同步异步区别的例子,不过都大同小异。比如,小明烧开水。

小明将水壶放在火上,立等水开。

小明将水壶放在火上,走开了,回头水开会响汽笛通知小明。

单从故事上看,当然第一个是同步,第二个是异步。或者还有个加强版。

立等水开是同步阻塞。小明将水壶放在火上,然后去看电视,不停地回来看水开了没,这叫做同步非阻塞。

真相

故事貌似完了。

  • 但是!考虑两种情况
    1. 现实中,异步可以没有回调函数。
    2. 如果异步没有回调函数,小明是不是还要不停地去检查水开了没有,这和同步非阻塞有什么区别?

回头考虑一下Unix的几种IO方式。

  • 同步阻塞
  • 同步非阻塞
  • 信号驱动
  • IO复用
  • 异步IO

如果不清楚细节,可以买本UNP支持一下。

这里一开始困扰我的是,它竟然将信号驱动归类在同步。

使用过信号机制的应该清楚,信号凌驾于一切状态,随时抢断进程。从应用层观察,这不就是JavaScript的异步抢断机制。比如document.onkeypress()。为什么在底层就是同步了?难道双方讨论的不是一个层面的事。

这里唯一可以确定的是,对于一个系统调用read。无论如何都要经过2个阶段。网卡读数据到内核缓冲区,接着复制数据到用户的缓冲区。同步IO无论如何最后都要在复制数据到用户空间时阻塞。

等等?这不是就像condition variable么?啊,同步和异步并不是对并行任务的描述,而是对并发任务的描述。也就是竞争状态。

在Linux, C/C++环境下,人们看到的是mutex。但Java环境下是synchronized。

也就是说通讯中的同步和多线程的同步其实是一回事

P.S. 曾有一篇“万恶之源”称那个几个IO复用方式为异步阻塞……

进一步解释

假设你从来没遇到多进程/线程/协程。总之是并行任务。那么你看的的函数调用只有两种情况,阻塞和非阻塞。这时不存在同步和异步之区别,或者说全算同步。

当出现(伪)并行任务时。首当其冲的必然是抽象意义的fork。这里才用得上同步,异步的概念。考虑下面两种流程

1)
     A0--\
A--<      ..-->B
     A1----/
2)
     A0...
A--<
     A1--->B
3)
     P0------  Q0      
P--< P1--- Q0
     P2---- Q0
C0<-- Q0
C1<-- Q0

简图1表达的是同步。A任务在执行过程中fork成A0和A1。在执行B任务之前,需要join操作,可以用任何同步原语实现。

简图2表达的是异步。A任务fork出的A0将执行到生命结束。A1将继续执行接下里的任务。其实它表达的意思更像是同步。

简图3表达的是异步回调,将P(roductor)的数据压入队列。C(onsumer)再从队列中取出数据。

(完)

 

Leave a Reply

Your email address will not be published. Required fields are marked *