首先,壅塞这个词来自操作系统的线程/进程的状态模型中,如下图:
一个线程/进程经历的5个状态,创建,就绪,运行,壅塞,终止。各个状态的转换条件如上图,个中有个壅塞状态,便是说当线程中调用某个函数,须要IO要求,或者暂时得不到竞争资源的,操作系统会把该线程壅塞起来,避免摧残浪费蹂躏CPU资源,等到得到了资源,再变成就绪状态,等待CPU调度运行。
壅塞调用是指调用结果返回之前,调用者会进入壅塞状态等待。只有在得到结果之后才会返回。
非壅塞调用是指在不能急速得到结果之前,该函数不会壅塞当前哨程,而会急速返回。
壅塞调用:比如 socket 的 recv(),调用这个函数的线程如果没有数据返回,它会一贯壅塞着,也便是 recv() 后面的代码都不会实行了,程序就停在 recv() 这里等待,以是一样平常把 recv() 放在单独的线程里调用。
非壅塞调用:比如非壅塞socket 的 send(),调用这个函数,它只是把待发送的数据复制到TCP输出缓冲区中,就急速返回了,线程并不会壅塞,数据有没有发出去 send() 是不知道的,不会等待它发出去才返回的。
拓展
如果线程始终壅塞着,永久得不到资源,于是就发生了去世锁。
比如A线程要X,Y资源才能连续运行,B线程也要X,Y资源才能运行,但X,Y同时只能给一个线程用(即互斥条件)用的时候其他线程又不能打劫。
A 有 X,等待 Y。
B 有 Y,等待 X。
于是A,B发生了循环等待,造成去世锁。给用户的觉得便是程序卡着不动了。
在写代码的时候要特殊把稳共享资源的利用,用旗子暗记量掌握好,避免造成去世锁。去世锁的解除有个著名的银里手算法
壅塞和挂起:壅塞是被动的,比如抢不到资源。挂起是主动的,线程自己调用 suspend() 把自己退出运行态了,某些时候调用 resume() 又规复运行。
线程实行完就会被销毁,如果不想线程被频繁的创建,销毁,怎么办?可以给线程里面写个去世循环,或者让线程有任务的时候实行,没任务的时候挂起,就像iOS中的 runloop 机制一样。线程就不会随便的终止了。
2. 同步,异步
同步:在发出一个同步调用时,在没有得到结果之前,该调用就不返回。
异步:在发出一个异步调用后,调用者不会急速得到结果,该调用就返回了。
同步例子
int n = func();
next();
// func() 的结果没有返回,next() 就不会实行,直到 func() 运行完。
异步例子
func(callback);
next();
...
void callback(int n) // func 结果回调
{
int k = n;
}
// func() 实行后,还没得出结果就立即返回,然后实行 next() 了
// 等到结果出来,func() 回调 callback() 关照调用者结果。
同步的定义看起来跟壅塞很像,但是同步跟壅塞是两个观点,同步调用的时候,线程不一定壅塞,调用虽然没返回,但它还是在运行状态中的,CPU很可能还在实行这段代码,而壅塞的话,它就肯定不在CPU中跑这个代码了。这便是同步和壅塞的差异。同步是肯定可以在,壅塞是肯定不在。
异步和非壅塞的定义比较像,两者的差异是异步是说调用的时候结果不会立时返回,线程可能被壅塞起来,也可能不壅塞,两者没紧要。非壅塞是说调用的时候,线程肯定不会进入壅塞状态。
上面两组观点,就有4种组合。
同步壅塞调用:得不到结果不返回,线程进入壅塞态等待。
同步非壅塞调用:得不到结果不返回,线程不壅塞一贯在CPU运行。
异步壅塞调用:去到别的线程,让别的线程壅塞起来等待结果,自己不壅塞。
异步非壅塞调用:去到别的线程,别的线程一贯在运行,直到得出结果。
3. 并发,并行
先从定义提及,定义经由我普通化了,原定义有点难明得。
并发是指一个韶光段内,有几个程序都在同一个CPU上运行,但任意一个时候点上只有一个程序在处理机上运行。
并行是指一个韶光段内,有几个程序都在几个CPU上运行,任意一个时候点上,有多个程序在同时运行,并且多道程序之间互不滋扰。 两者差异如下图
并行是多个程序在多个CPU上同时运行,任意一个时候可以有很多个程序同时运行,互不滋扰。
壅塞/非壅塞, 同步/异步的观点要把稳谈论的高下文:
1 .在进程通信层面, 壅塞/非壅塞, 同步/异步基本是同义词, 但是须要把稳区分谈论的工具是发送方还是吸收方。
发送方壅塞/非壅塞(同步/异步)和吸收方的壅塞/非壅塞(同步/异步) 是互不影响的。
在 IO 系统调用层面( IO system call )层面, 非壅塞 IO 系统调用 和 异步 IO 系统调用存在着一定的差别, 它们都不会壅塞进程, 但是返回结果的办法和内容有所差别, 但是都属于非壅塞系统调用( non-blocing system call )
2. 非壅塞系统调用(non-blocking I/O system call 与 asynchronous I/O system call) 的存在可以用来实现线程级别的 I/O 并发, 与通过多进程实现的 I/O 并发比较可以减少内存花费以及进程切换的开销。
附:PHP中同步壅塞的函数
mysql、mysqli、pdo以及其他DB操作函数sleep、usleepcurlstream、socket扩展的函数swoole_client同步模式memcache、redis扩展函数file_get_contents/fread等文件读取函数