理工科,在把概念混到一起之前,一定要咬文嚼字,把它们彻底弄清楚。
你说的这些很多都是八竿子打不着的概念,能并列就说明你压根没学懂。这时候不要着急往一块放,一个个理清楚是根本中的根本。
阻塞/非阻塞:这是从用户/任务安排者/调度者角度看待问题。不要和其它概念搅合到一起。
阻塞:当你开始一个任务、执行一个函数时,你必须等待这个任务完成、或者函数返回。这个等待时间可能很长,期间你不能做其他事。
比如,Windows下载了更新,要求你重启以应用更新时,这个更新就是阻塞的,在它完成前你的电脑不能做别的事。
再比如,你可以用select等待网络上传来消息;在消息传来之前,你的程序就阻塞了。什么时候消息来了,什么时候它才能继续执行。
非阻塞:启动一个任务后你就可以去干别的了,不需要等待它返回结果。
比如,你可以启动下载器下载一部电影;与之同时你可以做别的事。
再比如,你可以把select丢进一个线程,当网络上有消息传来时,这个线程会触发一个事件。此时select本身仍然是阻塞的,但你的程序主线程是非阻塞的,它完全可以支持你打字、看电影、玩游戏。
再举个例子:假设网络比较忙,你给小明发了个很大的图片。那么阻塞模式下,这个图片发完之前你什么都不能干,只能干等着;而非阻塞模式下,程序可以把图片先保存在缓冲区、等网络空闲了自动发送——而你完全可以继续敲字、继续和他聊天。这些聊天内容完全可以马上出现在小明的手机上,只是图片还需要三分钟他才能看到。
换句话说,讨论阻塞我们需要先明确观察者。对sendfile函数,它可能永远是阻塞的;但经过一定的技术处理,我们完全可以让我们的用户非阻塞的使用sendfile。
同步/异步:这也是从用户/任务安排者/调度者角度看问题,但它更偏向“我们会得到什么”。
同步:程序/函数返回我们马上就得到执行结果。
异步:程序/函数返回我们只能拿到一张“凭据”,在一定时间后,我们可以凭这张“凭据”取得执行结果。
比如,你到医院看病,医生望闻问切之后给你下了诊断书,这就是同步调用。
反之,你到医院看病,先去拍CT,然后拿到个条码。过了两个半小时后,你拿这张条码到取影像处拿到了你的片子和医生诊断书,这就是异步调用。
大多数时候,同步调用是阻塞的,异步调用是非阻塞的。同步改异步也是常用的把阻塞式调用改成非阻塞调用的通用手段。
当然,你也完全可以搞一个奇葩实现,把异步调用(的某些步骤)弄成阻塞的。
换句话说,这个概念和阻塞/非阻塞存在一定的关系,但彼此仍然是正交的。
并发是完全从任务调度角度看待问题;而并行则要求任务同时执行。
并发:你可以同时安排我做20个任务;但这些任务我以什么顺序做、会不会同时做,这你管不着。
并行:当我做这20个任务时,发现某些任务是可以同时做的——比如,我可以在给你做饭的同时,接你老师的电话。
比如,这个学期你要学习语文数学物理化学,这就是并发。但学语文时你就不能学数学,换句话说没法并行。
特别的,如果一个系统是阻塞的,那么显然我们就不可能并发的给它安排任务。不能并发的安排任务,那么当然也就不可能并行——因为你一次只能领一个任务。
分布式:分布式说的是软件架构。简单说,把任务分解、放到联网的一堆电脑上执行,这就是分布式。