Python多进程vs多线程

0x00前言

  近期处理亿级数据,发现对于耗费CPU的程序(正则检索等)而言Python的多线程由于线程调度还不如单线程效率高,然而多CPU环境下,多线程与单线程最多只能使得单个CPU达到100%利用率。利用Python多进程(multiprocessing)可以使得多个CPU同时工作,利用效率大大提升

0x01原理介绍

1.1CPU密集型和IO密集型

  CPU密集型:程序线性执行,大量占用CPU,总是接近100%(如:正则匹配替换大量文本)
  IO密集型:程序大量时间花费在等待I/O操作,CPU总是闲置,在10%左右(如:网络请求)

1.2python多线程和多进程

  python的多线程和其他编程语言的多线程有很大的区别,python多线程即使在多核CPU主机上也只能使用一个CPU,不是真正意义上的并发执行。
  对于IO密集型的程序而言,使用多线程技术可以在CPU阻塞等待的间隔执行其他操作,可以提高CPU的使用效率,PS:gevent库协程技术也是只在IO密集型程序比较有效
  对于CPU密集型的程序而言,原本CPU就是一直繁忙的状态,强制使用多线程技术,不会增加CPU的利用效率,却增加线程切换的代价,可能导致多线程的执行效率还不如单线程的执行效率。在多核CPU主机可以采用pytho多进程(multiprocessing)使得程序同时使用多个CPU,可以达到程序真实意义上的并行(进程数不要超过CPU核数)

0x02实际对比

测试环境:
  Ubuntu系统
  16核CPU主机

2.1多线程测试程序

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Queue
import threading
queueLock = threading.Lock()
workQueue = Queue.Queue()
thread_num = 11
threads = []

class MyThread (threading.Thread):
def __init__(self, Queue,id):
threading.Thread.__init__(self)
self.q = Queue
self.id = id

def run(self):
while not workQueue.empty():
get_info(self.q.get(),self.id)

def get_info(data,threading_id):
for i in range(1000000):
a=str(threading)+data

def main():
for i in range(1000):
workQueue.put(str(i))
for i in range(thread_num):
thread = MyThread(workQueue, i)
thread.start()
threads.append(thread)
for t in threads:
t.join()


if __name__ == '__main__':
main()

运行python程序,监控CPU使用情况只有1个CPU在使用状态

multithreading

2.2多进程测试

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import multiprocessing
processors = []
processor_num = 11
workQueue = multiprocessing.Queue()
def single_processor(q,id):
while not workQueue.empty():
get_info(q.get(),id)

def get_info(data,processor_id):
for i in range(1000000):
a=str(processor_id)+data


def main():
for i in range(1000):
workQueue.put(str(i))
for i in range(processor_num):
p = multiprocessing.Process(target=single_processor, args=(workQueue,i))
p.start()
processors.append(p)
for i in processors:
i.join()

if __name__ == '__main__':
main()

运行python程序,监控CPU使用情况可以看出有11个CPU均处于100%利用状态(注:进程数最好不要超过CPU核数)

multiprocessing

0x03总结

当程序功能需要大量使用CPU,没有IO等待延迟即程序为CPU密集型的时候,且主机为多核的情况下,Python多进程可以达到极好的效率。