GIL机制导致如下结果:
Python的多线程程序并不能利用多核CPU的优势 (比如一个使用了多个线程的计算密集型程序只会在一个单CPU上面运行)
python多线程适合io操作密集型的任务(如socket server 网络并发这一类的);
python多线程不适合cpu密集操作型的任务,主要使用cpu来计算,如大量的数学计算。
那么如果有cpu密集型的任务怎么办,可以通过多进程来操作(不是多线程)。
假如CPU有8核,每核CPU都可以用1个进程,每个进程可以用1个线程来进行计算。
1、线性模式测试
1 import requests 2 import time 3 from threading import Thread 4 from multiprocessing import Process 5 6 #定义CPU密集的计算函数 7 def count(x, y): 8 # 使程序完成150万计算 9 c = 0 10 while c < 500000: 11 c += 1 12 x += x 13 y += y 14 15 #定义IO密集的文件读写函数 16 def write(): 17 f = open("test.txt", "w") 18 for x in range(5000000): 19 f.write("testwrite ") 20 f.close() 21 22 def read(): 23 f = open("test.txt", "r") 24 lines = f.readlines() 25 f.close() 26 27 def io(): 28 write() 29 read() 30 31 #定义网络请求函数 32 _head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36'} 33 url = "http://www.tieba.com" 34 def http_request(): 35 try: 36 webPage = requests.get(url, headers=_head) 37 html = webPage.text 38 return {"context": html} 39 except Exception as e: 40 return {"error": e} 41 42 #--------------------------------------- 43 #CPU密集操作 44 t = time.time() 45 for x in range(10): 46 count(1, 1) 47 print("Line cpu", time.time() - t) 48 49 # IO密集操作 50 t = time.time() 51 for x in range(10): 52 io() 53 print("Line IO", time.time() - t) 54 55 # 网络请求密集型操作 56 t = time.time() 57 for x in range(10): 58 http_request() 59 print("Line Http Request", time.time() - t)
--运行---------------------结果:
('Line cpu', 97.26900005340576)
('Line IO', 24.319000005722046)
('Line Http Request', 209.94899988174438)
2、线程模式测试
1 #定于线程公共函数 2 def mythread(fun,*args): 3 counts = [] 4 for x in range(10): 5 thread = Thread(target=fun, args=args) 6 counts.append(thread) 7 thread.start() 8 e = counts.__len__() 9 while True: 10 for th in counts: 11 if not th.is_alive(): 12 e -= 1 13 if e <= 0: 14 break 15 16 #测试多线程并发执行CPU密集操作所需时间 17 t = time.time() 18 mythread(count,1,1) 19 print("thread cpu ",time.time() - t) 20 21 #测试多线程并发执行IO密集操作所需时间 22 t = time.time() 23 mythread(io) 24 print("thread IO ",time.time() - t) 25 26 #测试多线程并发执行网络密集操作所需时间 27 t = time.time() 28 mythread(http_request) 29 print("Thread Http Request", time.time() - t)
--运行---------------------结果:
('thread cpu ', 102.20300006866455)
('thread IO ', 654.5730001926422)
('Thread Http Request', 21.170999765396118)
3.进程模式测试
1 def myprocess(fun,*args): 2 counts = [] 3 for x in range(10): 4 process = Process(target=fun,args=args) 5 counts.append(process) 6 process.start() 7 e = counts.__len__() 8 while True: 9 for th in counts: 10 if not th.is_alive(): 11 e -= 1 12 if e <= 0: 13 break 14 15 if __name__ == '__main__': #没这句会报错。 16 #测试多进程并发执行CPU密集操作所需时间 17 t = time.time() 18 myprocess(count,1,1) 19 print("Multiprocess cpu", time.time() - t) 20 21 #测试多进程并发执行IO密集型操作 22 t = time.time() 23 myprocess(io) 24 print("Multiprocess IO", time.time() - t) 25 26 #测试多进程并发执行Http请求密集型操作 27 t = time.time() 28 myprocess(http_request) 29 print("Multiprocess Http Request", time.time() - t)
--运行---------------------结果:
('Multiprocess cpu', 20.168999910354614)
('Multiprocess IO', 11.82699990272522)
('Multiprocess Http Request', 21.805000066757202)
实验结果
CPU密集型操作 | IO密集型操作 | 网络请求密集型操作 | |
单线程操作 | 97 | 24 | 310 |
多线程操作 | 102 | 654 | 21 |
多进程操作 | 20 | 12 | 22 |
通过上面的结果,我们可以看到:
- 多线程在IO密集型的操作下似乎也没有很大的优势,在CPU密集型的操作下明显地比单线程线性执行性能更差,但是对于网络请求这种忙等阻塞线程的操作,多线程的优势便非常显著了
- 多进程无论是在CPU密集型还是IO密集型以及网络请求密集型(经常发生线程阻塞的操作)中,都能体现出性能的优势。不过在类似网络请求密集型的操作上,与多线程相差无几,但却更占用CPU等资源,所以对于这种情况下,我们可以选择多线程来执行
一句话总结:cpu和io密集操作使用多进程,网络操作使用多线程