Python中单线程、多线程和多进程的效率对比实验

时间:2022-02-01 16:39:38

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\n")
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密集操作使用多进程,网络操作使用多线程