多进程与多线程孰优孰劣?
开始正文之前。我们先来注意这样几点:
1、什么是进程?
正在执行的一个程序或者一个任务,负责执行任务的是CPU。进程是用来把资源集中到一起的,简而言之,进程是资源单位,或者说资源集合。
2、什么是线程?
线程是CPU上的执行单位。同一个进程内的多个线程共享该进程内的地址资源。创建线程的开销远小于创建进程的开销。
3、进程和线程的区别
① 每启动一个进程,这个进程内至少得有一个线程。
② 进程本身只是一个资源单位,并不是真正执行,进程内的线程才是执行单位。
③ 一个进程内可以有多个线程,且进程在内存中相互隔离,而同一个进程内的线程是共享资源的,各线程之间地位是平等的。
④ 进程更消耗资源,而线程开销小,是在已有的进程内占用。
正文开始
-------------------------------------------------------------------------------------------------------------------
看了以上这些,大家肯定认为多线程是优于多进程的,那么多线程任何时候都优于多进程吗?
我们慢慢接着看,用实例说话。
计算机程序进行的操作粗略可分为计算密集型和IO(输入输出)密集型两种。我们通过分别开启多进程和
多线程测试计算机的运行时间,以此来判断多进程和多线程的效率高低,即优劣之分。
第一种:计算密集型
#!/user/bin/env python3
# -*- coding:utf-8 -*-
# write by congcong
from multiprocessing import Process
from threading import Thread
import time
import os
def task():
res = 10
for i in range(10000000):
res *= i
if __name__ == "__main__":
t_list = []
print(os.cpu_count()) # 显示本机cpu核心数--》4
start_time = time.time() # 程序开始时刻
for i in range(20):
p = Process(target=task) # 开启多个进程
t = Thread(target=task) # 开启多个线程
#t_list.append(p) # 添加进程到列表
t_list.append(t) # 添加线程到列表
for t in t_list: #依次启动进程\线程
t.start()
for t in t_list: # 使用join方法保证每个进程\线程都执行完毕
t.join()
stop_time = time.time() # 程序结束时刻
print('程序运行总时长:%s'%(stop_time-start_time))
猜一猜,哪一个的效率更高,是多进程?还是多线程?谜底在下方...
#多进程下程序运行总时长:8.04701852798462
#多线程下程序运行总时长:11.769368171691895
为什么如此呢?原因是什么?我们稍后再议,先接着比较第二种情况(IO密集型)时多进程和多线程的表现。
第二种情况:IO密集型
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# write by congcong
from multiprocessing import Process
from threading import Thread
import time
import os
def task():
time.sleep(2) # 模拟IO操作
if __name__== "__main__":
t_list = []
print(os.cpu_count()) # 显示本机cpu核心数--》4
start_time = time.time() # 程序开始时刻
for i in range(100):
#p = Process(target=task) # 开启多个进程
t = Thread(target=task) # 开启多个线程
#t_list.append(p) # 添加进程到列表
t_list.append(t) # 添加线程到列表
for t in t_list: # 依次启动进程\线程
t.start()
for t in t_list: # 使用join方法保证每个进程\线程都执行完毕
t.join()
stop_time = time.time()
print('程序运行总时长:%s'%(stop_time-start_time))
大家再猜一下,这时候两者的效率有何不同?谜底见下方:
# 开启多个进程 程序运行总时长--8.04701852798462
# 开启多个线程 程序运行总时长--2.011910915374756
耐心看到这里的同学大概已经明白了,多进程和多线程各有优劣,没有谁能无敌天下,
要分不同的情况分析才合理,针对以上两种情况的解释如下:
针对第一种情况(计算密集型),因为Python有了GIL的存在,同一时刻同一进程中只有一个线程被执行。我测试用的电脑CPU是4核心,所以所以多进程能够利用多核的优势。
针对第二种情况(IO密集型),大部分时间都消耗在创建进程上,而对于多线程而言,他们都位于一个进程下,并且开线程的消耗远远小于开进程,所以耗时远远小于开多进程。
而这并不是全部,更加详细的分析见下面:
我们把多进程和多线程视为两种方案:
方案一:开启100个进程
方案二:一个进程下,开启100个线程
#假如我们的电脑是单核CPU,分析结果如下:
如果100个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜
如果100个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜
#假如我们的电脑是多核CPU,分析结果如下:
如果100个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜
如果100个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜
所以,我们不难得出以下的结论:
由于现在的计算机基本上都是多核的,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。
读书原为修身,正己才能正人正世;不修身不正己而去正人正世者,无一不是盗名欺世;你把念过的书能用上十之一二,就是很了不得的人了。——朱先生