博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
阻塞、非阻塞、同步、异步之个人理解
阅读量:4331 次
发布时间:2019-06-06

本文共 2161 字,大约阅读时间需要 7 分钟。

阻塞、非阻塞、同步、异步

先抛观点:

对于一个纯粹的 IO 模型而言,不存在异步阻塞的 IO 模型,这两个词搭在一起就是有歧义的。

 

如果我们把整个程序开发过程中的角色分成两类:调用者和被调用者,这样就能很好地理解关于 IO 模型那些概念。

调用者:写程序的人,这个可以映射成所有已知细节的函数(确实知道函数的细节,或者说函数是这个人实现的)。

被调用者:给调用者提供调用函数的人,这个可以映射成所有对于调用者而言未知细节或不愿知道细节的函数(无法获知或不关心)。

一个程序必然由调用者和被调用者构成,他们可能会有交互,也有可能不会有交互(这种情况不存在被调用者)。

 

同步:

调用者询问被调用者,被调用者对于询问的内容给于响应。

具体体现:

对于一个由自己实现的函数 A内部(以 C 为例,任何一个编码过程几乎都是在实现函数)(因为这个函数是自己写的所以调用者视角),尝试调用未知细节或不愿知道细节的函数B,不论如何结果都会以函数返回值的形式呈现在函数 A 内。

 

阻塞:

陷入系统调用,系统发现 IO 会在很长时间后完成,选择挂起当前进程,将 CPU 控制权调度给其他进程。表象为,某个被调用者得不到第一时间的返回。

非阻塞:

类似于阻塞,就很好理解,系统调用会马上返回。但它不一定会返回调用者期望的数据,因为数据必定没有那么快准备好。那么在非阻塞这个概念成立的时候,必然是同步的获取信息方式,因为信息是以被调用的未知细节的函数的返回值的形式呈现给调用者的。

 

那么我们讨论阻塞和非阻塞的时候实际更多的是在关心什么呢?

操作系统切换进程的开销,阻塞的时候 CPU 并没有闲下来而是交给了别的调用者去使用(不过保存和切换上下文的时间和资源被消耗了),而非阻塞的时候 CPU 也没有停下来,只不过他可能会因为当前调用者(已经实现的业务函数)的CPU 计算需求并不充足,而导致 CPU 被无意义的忙循环给浪费,其他调用者得不到充分利用 CPU。

 

异步:

调用者将询问请求注册给被调用者,被调用者并不响应数据。被调用者,会在一个对调用者而言不知情的时间通知调用者。

具体体现:

对于一个由自己实现的函数 A内部(以 C 为例,任何一个编码过程几乎都是在实现函数)(因为这个函数是自己写的所以调用者视角),尝试调用未知细节或不愿知道细节的函数B,告诉B 自己的请求。B回应并不以返回值回应,B 会在某个 A 不知情的时刻调用 A 之前提供过的函数指针C,并将信息数据以参数或全局变量的形式呈现在C 内。因为异步通常是以操作系统对信号的回调处理呈现的,所以大多数异步过程是可以被抢占的。

 

这样就很明朗了,如果我们以一个纯粹的角度去看待一段 IO 处理的代码,被看待的一方(被调用者)是纯粹的系统调用。那么异步阻塞是必然不存在的,因为异步 API 本身不会因为某种原因阻塞。

 

但是如果我们用一个更宽阔的眼光去看待一段被封装过的 IO 处理代码,例如(伪代码):

// NewRead 内部的 readAsynBlock 方法的定义 NewRead.readAsynBlock(){while(1){ // 假定read_without_block 是非阻塞读的 APIif(a = read_without_block()){  this.handler(a);   return;}}func A{newRead.handler = func(data){
echo data} a = newRead.readAsynBlockread();}

这样的处理方式,如果对于 A 函数而言它屏蔽了或不关心 newRead.read(),这就是异步阻塞式的。如果 A 对于 newRead.read()是知情的,则是同步非阻塞式的。

再如果,被调用者在 readAsynNoBlock 内部添加定时器,定时调用非阻塞 read API,有正返回值则回调内容。这对于一切都不知情的 A 而言,就成了异步非阻塞的 IO 模型。

// NewRead 内部的 readAsynNoBlock 方法的定义NewRead.readAsynNoBlock(){// 如果没有添加过定时器if(!already_add) // 添加定时器100毫秒执行一次操作    Timer.add(func(newRead){if(a = read_without_block()){  this.handler(a);  return;}},this,100);}func A{newRead.handler = func(data){
echo data} a = newRead.readAsynNoBlockread();echo 123;}

 

所以对于不同的调用者和被调用者的语境,IO 模型是可以互相转化的,被调用者对相对底层的 IO 模型的封装可以改变调用者的编程方式。但对于性能而言,或许从纯粹的角度去描述 IO 模型是更有意义的。

 

posted on
2017-05-25 00:52  阅读(
...) 评论(
...) 收藏

转载于:https://www.cnblogs.com/TsAihS/p/6901742.html

你可能感兴趣的文章
BABOK - 需求分析(Requirements Analysis)概述
查看>>
第43条:掌握GCD及操作队列的使用时机
查看>>
Windows autoKeras的下载与安装连接
查看>>
CMU Bomblab 答案
查看>>
微信支付之异步通知签名错误
查看>>
2016 - 1 -17 GCD学习总结
查看>>
linux安装php-redis扩展(转)
查看>>
Vue集成微信开发趟坑:公众号以及JSSDK相关
查看>>
技术分析淘宝的超卖宝贝
查看>>
i++和++1
查看>>
react.js
查看>>
P1313 计算系数
查看>>
NSString的长度比较方法(一)
查看>>
Azure云服务托管恶意软件
查看>>
My安卓知识6--关于把项目从androidstudio工程转成eclipse工程并导成jar包
查看>>
旧的起点(开园说明)
查看>>
生产订单“生产线别”带入生产入库单
查看>>
crontab导致磁盘空间满问题的解决
查看>>
java基础 第十一章(多态、抽象类、接口、包装类、String)
查看>>
Hadoop 服务器配置的副本数量 管不了客户端
查看>>