进程线程以及协程

来源:互联网 发布:霸道总裁小说知乎 编辑:程序博客网 时间:2024/06/10 05:29

http://www.godiscoder.com/?p=521

进程线程以及协程

前段时间在看nodejs,主要是因为nodejs的IO处理性能非常高,号称能够同时支持上万的长连接,这个当时太让我惊讶了,主要是了解其实现原理以及设计思想。

要说起这个实现原理,必须要从操作系统中最基本重要的概念——进程来开始逐步了解现代现代才做系统是如何进行程序调度的。

进程是操作系统中最重要的一个概念,基本上是说程序执行的实例,(以unix系统为例)它包括正在执行的程序代码以及其对应的数据,还包括了进程所占用的虚拟内存,信号量,文件目录,文件句柄等等。可以看出,创建一个进程代价是比较高的,所以操作系统中的进程数往往是有限的,不能无限制的增长,因为他要耗费太多的系统的资源。进程之间可以互相通信,通过这种方式,来完成进程之间的沟通与协作。进程间通信的主要有两种方式:第一种是信号量,通过向其他进程发送信号,内核接收到这个请求,然后通知接受信号的进程来处理;第二个种方式是通过管道,两个进程共享一个管道信息,一个进程往往管道的一段写数据,另外一个进程从管道的另外一端接受数据,从实现原理来看,更像是两个进程共享一段内存信息。在进程调度上,都是由操作系统内核进行调度,进程调度比较复杂,由专门的算法来实现进程调度,一般都有时间片的调度算法那,这里就不说了。正常情况下,一个进程有一定的执行时间,当发生以下几种情况的时候,进程会被迫让出时间片,腾出CPU给其他进程,包括:1 当期正在执行的进程陷入io,被阻塞 2线程被人为中断,例如给线程发送中断信号 3 进程用完时间片 4 有优先级更高的进程要执行,被抢占。 如果进程过多,调度就越频繁,由于进程一次调度,在系统上,需要做很多的工作,比如:保存当前进程的调用栈信息,cpu各个寄存器信息,虚拟内存交换,保护相关的资源等等,所以进行一次进程切换的代价是比较高的。

从上面的分析,我们从三个维度来总结以下进程相关的特性,

资源占用:比较多

进程通信:效率比较低

上下文切换:慢

 

由于创建进程的代价太高,所以在操作系统中,又出现了线程的概念,简单的说,就是一个进程可以拥有多个线程,每个线程都会共享进程所占用的资源信息,包括虚拟内存,文件资源等等。在这个方面,线程所占用的资源远远小于进程,系统中就可以创建相对数量较多的线程,这些线程共享一个进程所占有的所有资源。在unix操作系统中,线程也是用进程表示的,只不过这些进程可以共享了父进程相关的信息,这里成为轻量级进程。 在线程之间,不仅仅可以通过进程之间的通信方式:信号量,管道,还可以通过共享内存的方式进行通信,在java里面就表现的比较明显,例如两个线程之间可以通过一个实例变量(例如消息队列)进行通信,这种通信方式很高效,毕竟访问内存是非常快的。在调度层面,同一个线程组(共享一个进程)的切换相对比较高效,但是不同线程组之间的切换其实和进程切换效率差不多。

从上面的分析,也总结以下以下线程的特性

资源占用:一般

线程通信:效率高

上下文切换:一般

 

对于进程和线程来说,都是通过操作系统内核进行调度的,是抢占式的,也就是说,进程和线程还没有运行完成,是可以被其他进程或者线程进行抢占的,进程调度这么设计,是完全有道理的,避免由于一个进程无限运行,其他进程无法得到cpu的时间,导致整个系统死机。但是进程之间切换也是很耗时的,但可以考虑,如果保证业务处理会在有限的时间内完成,那么就没有必要采用抢占式调度的机制。同时如果任务永远不会被阻塞(系统必须支持非阻塞IO),那么就可能采取一种简单的调度策略,这种策略就是顺序执行将要处理的任务列表。

假设采用这种调度方式,就是由一个线程循环处理所有的任务,要想提高性能,就必须满足以下几个条件:

1 任务执行的时间比较短

假设任务执行时间都比较长,远远高于线程切换的代价,那完全可以采用单独一个线程进行处理,没有必要采用这种复杂的方案

2 任务所依赖的线程不能被阻塞

相当于执行任务的线程要被阻塞,相当于每个任务里面不能调用阻塞线程相关的操作,否则后续的任务就无法执行,整体的效率反而比多线程的效率低

3 任务之间是没有依赖的

任务之间彼此独立,没有依赖关系,也就是说不会涉及到同步和互斥。

 

这里面会涉及到一个问题,就是这个执行的任务如果调用了非阻塞io,,需要等io完成了,才能进行后续的业务处理。为了解决这种情况,我们必须保存这个任务的上下文,然后跳过这个任务,调度程序会执行下一个任务,等操作系统io完成之后,通知执行线程,那么这个线程会找到当时没有执行完成的任务,继续执行。这里面其实也会涉及到任务的上下文切换,但是这种切换代价很低,完全可以在线程里面实现,不需要调用内核完成切换,避免性能开销。

以上说的就是一个coroutine机制,这种机制的思路就是在用户层设计一个任务调度任务,这个任务名字就要做协程,比线程更轻量级,协程有很多限制。并不是所有的业务都适合用这种方式来实现。

 

可以看出协程的一些特性:

占用资源:很少

协程通信:不能同步通信,只能采取异步消息通信,效率高

上下文切换:很快

 

下面一幅图说明这三者的关系:

进程线程以及协程

0 0
原创粉丝点击