关于进程、线程、协程
1.进程:由OS来管理,每个进程都有自己独立的内存空间,进程之间通讯主要是通过信号传递的方式来实现的,实现方式有多种,信号量,管道,事件等,任何一种方式的通讯效率都需要过内核,导致通讯效率比较低.由于是独立的内存空间,所以上下文切换的时候需要保存当先调用栈的信息,cpu各寄存器的信息,虚拟内存,以及打开的相关句柄等信息,所以导致上下文切换的代价非常高,因此进程并不适合大量创建。
2.线程:也是由OS来管理的,一个进程可以拥有多个线程,但是其中每个线程会共享父进程像OS申请的资源,这个包括虚拟内存,文件等,由于是共享资源,所以创建线程所需要的系统资源占用比进程小很多,相应的可创建的线程数量也变得相对多很多.线程时间的的通讯除了可以使用进程之间通讯的方式以外还可以通过共享内存的方式进行通信,这个在java里面多个线程就可以通过一个共享的Queue来完成通讯,由于是在内存里面的访问,所以这个速度你完全可以想象到比通过内核要快很多.另外在调度方面还是由于内存是共享的,所以上下文切换的时候需要保存的东西就像对少一些,这样一来上下文的切换也变得高效,但是有一种情况上下文切换的效率和进程间切换差不多,那就是不同线程组时间的切换,你基本上可以认为一个线程组就是一个进程(效率上这么认为,实际上不是)
3.协程:上面提到的进程和线程都是由OS来控制其切换的,使用的是抢占式[注一].协程是用户层面的东东,他的切换是由用户自己来决定的,你可以想想用户创建了几个线程,然后每个线程都是循环按照指定的任务清单顺序完成不同的任务,当任务被堵塞的时候执行下一个任务,当恢复的时候再回来执行这个任务,任务之间的切换只需要保存每个任务的上下文内容,就像直接操作栈一样的,这样就完全没有内核切换的开销,所以上下文的切换非常快.另外协程还需要保证是非堵塞的且没有相互依赖,协程基本上不能同步通讯,多采用一步的消息通讯,效率比较高.比较具有代表性的是golang里面goroutine.
注一:
抢占式:就是当一个进程在运行,另一个更高优先级的进程就绪了,那么要立刻中止当前进程转而去执行那个更高优先级的进程.
非抢占式:就是所有进程的优先级一样,只有这个进程运行完了,或所分到的时间片用完了,又或是一个调度时钟周期到了才会交出系统运行权.
不论是抢占式还是非抢占式在一个CPU定时时钟产生后就有权进行任务切换.