首先使用python的多进程和多线程来完成一个简单的任务,做一个直观的对比:往一个数组中疯狂放值。
1. 简单玩法(单线程)
import time
nb_repeat = 50
def a_complex_operation(*args):
a = []
for x in range(999999):
a.append(x)
return None
t1 = time.time()
for _ in range(nb_repeat):
a_complex_operation()
print time.time()-t1
耗时4.82s
2.多进程版本
from multiprocessing import Pool
nb_repeat = 50
def a_complex_operation(*args):
a = []
for x in range(999999):
a.append(x)
return None
pool = Pool(processes=nb_repeat)
results = pool.map(a_complex_operation, [None for _ in range(nb_repeat)])
耗时 2.74s
3.多线程玩法
from threading import Thread
import time
nb_repeat = 50
def a_complex_operation(*args):
a = []
for x in range(999999):
a.append(x)
return None
t1 = time.time()
threads = []
for _ in range(nb_repeat):
threads.append(Thread(target=a_complex_operation))
[x.start() for x in threads]
[x.join() for x in threads]
print time.time()-t1
耗时14.088s。
岂有此理!!!,怎么回事?
说到为什么使用多线程反而耗时会更久,就不得不提GIL, Global Interpreter Lock.
GIL全局解释器锁是编程语言中的一种控制线程同步的机制。在同一时刻,即使机器有多核cpu,GIL只允许一个线程运行,用来避免多个线程共享非线程安全的代码片。python使用的CPython解释器和ruby使用MRI解释器都使用了GIL机制。
由于上面代码执行的属于计算密集型(cpu bound)任务,加之GIL的控制,导致多线程性能下降。而多进程(multiprocessing)充分利用了多核cpu。因为多个进程可以同时(同一时刻)运行在多个cpu上,达到真正的并行。每个进程都有单独的GIL。
那是不是说python中multiprocessing就所有的场景里都是最好的终极方案呢? 答案肯定不是。上面已经说到在计算密集型(cpu bound)任务中,python多线程是低效的。但是在处理网络任务这种io密集型任务的场景中,python多线程还是很有优势的。1)首先,从操作系统原理上分析,线程肯定比进程轻量。2)在多线程执行io任务时,每个线程的大部分时间是在等待io,所以GIL控制所带来的影响可以忽略不计。