多进程和多线程应用场景

开发程序的方案阶段经常需要用到多线程或者多进程。本文介绍两种方式的优劣性:
一、多线程 优点:
1. 无需跨进程边界
2. 程序逻辑和控制方式简单
3. 所有线程可以直接共享内存和变量等
4. 线程方式消耗的总资源比进程方式好
缺点:
1. 每个线程与主程序共用地址空间,受限于2GB地址空间
2. 线程之间的同步和加锁控制比较麻烦
3. 一个线程的崩溃可能影响到整个程序的稳定性
4. 到达一定的线程数程度后,即使再增加CPU也无法提高性能
【多进程和多线程应用场景】5. 线程能够提高的总性能有限,而且线程数量较大时,线程本身的调度开销不小
提高多线程程序效率的一般方法:

  • 不要频繁创建,销毁线程,
  • 使用线程池减少线程间同步和通信(最为关键)
  • 避免需要频繁共享写的数据
  • 合理安排共享数据结构,避免伪共享(false sharing)
  • 使用非阻塞数据结构/算法
  • 避免可能产生可伸缩性问题的系统调用(比如mmap)
  • 避免产生大量缺页异常,
  • 尽量使用Huge Page可以的话使用用户态轻量级线程代替内核线程
二、多进程 三、总结 多线程比多进程成本低,但性能更低。在UNIX环境,多进程调度开销比多线程调度开销,没有显著区别,就是说,UNIX进程调度效率是很高的。内存消耗方面,二者只差全局数据区,现在内存都很便宜,服务器内存动辄若干G,根本不是问题。多进程是立体交通系统,虽然造价高,上坡下坡多耗点油,但是不堵车。多线程是平面交通系统,造价低,但红绿灯太多,老堵车。
多线程的优点:无需跨进程边界; 程序逻辑和控制方式简单; 所有线程可以直接共享内存和变量等; 线程方式消耗的总资源比进程方式好; 多线程缺点:每个线程与主程序共用地址空间,受限于2GB地址空间; 线程之间的同步和加锁控制比较麻烦; 一个线程的崩溃可能影响到整个程序的稳定性; 到达一定的线程数程度后,即使再增加CPU也无法提高性能,例如Windows Server 2003,大约是1500个左右的线程数就快到极限了(线程堆栈设定为1M),如果设定线程堆栈为2M,还达不到1500个线程总数; 线程能够提高的总性能有限,而且线程多了之后,线程本身的调度也是一个麻烦事儿,需要消耗较多的CPU多进程优点:每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系; 通过增加CPU,就可以容易扩充性能; 可以尽量减少线程加锁/解锁的影响,极大提高性能,就算是线程运行的模块算法效率低也没关系; 每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限非常大 多线程缺点:逻辑控制复杂,需要和主程序交互; 需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算 多进程调度开销比较大; 最好是多进程和多线程结合,即根据实际的需要,每个CPU开启一个子进程,这个子进程开启多线程可以为若干同类型的数据进行处理。当然你也可以利用多线程+多CPU+轮询方式来解决问题……
日常写程序时,我们经常会听到一种说法:“使用多线程,可以增加系统吞吐率,或是可以增加系统扩展性。”的确,对于一个多线程的系统来说,在有合理的资源分配的情况下,可以增加系统中处理请求操作的资源实体,进而提升系统能够同时处理的请求数,即吞吐率。下面的左图是我们采用多线程时所期待的结果。
但是,请你注意,通常情况下,在我们采用多线程后,如果没有良好的系统设计,实际得到的结果,其实是右图所展示的那样。我们刚开始增加线程数时,系统吞吐率会增加,但是,再进一步增加线程时,系统吞吐率就增长迟缓了,有时甚至还会出现下降的情况。
多进程和多线程应用场景
文章图片

为什么会出现这种情况呢?一个关键的瓶颈在于,系统中通常会存在被多线程同时访问的共享资源,比如一个共享的数据结构。当有多个线程要修改这个共享资源时,为了保证共享资源的正确性,就需要有额外的机制进行保证,而这个额外的机制,就会带来额外的开销。

    推荐阅读