参考博文:https://blog.csdn.net/dcrmg/article/details/78231845
1.python的GIL(全局解析器锁)在单核情况下对性能的影响可以忽略不计。
2.python由于GIL的存在在多核CPU的情况下Thread的表现非常糟糕,但Process则不受GIL的影响。
一.multiprocessing中Process是一个类,用于创建进程,以及定义进程的方法,Process类的构造函数是:
def __init__(self, group=None, target=None, name=None, args=(), kwargs={})
参数含义:
常用函数:
# coding=utf-8
import multiprocessing
import time
import cv2
def daemon1(image):
name = multiprocessing.current_process().name
for i in range(50):
image = cv2.GaussianBlur(image, (3, 3), 1)
time.sleep(0.1)
print 'daemon1 done!'
cv2.imshow('daemon1', image)
cv2.waitKey(0)
#cv2.destroyWindow()
def daemon2(image):
name = multiprocessing.current_process().name
for i in range(50):
image = cv2.GaussianBlur(image, (3, 3), 1)
time.sleep(0.5)
print 'daemon2 done!'
cv2.imshow('daemon2', image)
cv2.waitKey(0)
#cv2.destroyWindow()
if __name__ == '__main__':
t1 = time.time()
number_kernel = multiprocessing.cpu_count()
print 'We have {0} kernels'.format(number_kernel)
p1 = multiprocessing.Process(name='daemon1',
target=daemon1, args=(cv2.imread('./yy.jpg'),))
p1.daemon = False
p2 = multiprocessing.Process(name='daemon2',
target=daemon2, args=(cv2.imread('./hi.png'),))
p2.daemon = False
p1.start()
p2.start()
print 'p1 is {0}'.format(p1.is_alive())
p1.terminate()
p1.join()
print 'p1 is {0}'.format(p1.is_alive())
print 'p2 is {0}'.format(p2.is_alive())
p2.join()
t2 = time.time()
print '!!!!!!!!!!!!!!!!!!!!OK!!!!!!!!!!!!!!!!!!!!!'
print 'total time is {0}'.format(t2 - t1)
print 'p1.exitcode = {0}'.format(p1.exitcode)
print 'p2.exitcode = {0}'.format(p2.exitcode)
运行结果:
We have 2 kernels
p1 is True
p1 is False
p2 is True
daemon2 done!
!!!!!!!!!!!!!!!!!!!!OK!!!!!!!!!!!!!!!!!!!!!
total time is 71.5577499866
p1.exitcode = -15
p2.exitcode = 0
二.在multiprocessing中使用pool
如果有50个任务要执行, 但是 CPU 只有4核, 你可以创建50个进程来做这个事情。但是大可不必,徒增管理开销。如果你只想创建4个进程,让他们轮流替你完成任务,不用自己去管理具体的进程的创建销毁,那 Pool 是非常有用的。
Pool 是进程池,进程池能够管理一定的进程,当有空闲进程时,则利用空闲进程完成任务,直到所有任务完成为止,如果需要多个子进程时,使用进程池(pool)来(自动)管理各个子进程更加方便:
与Process类创建进程的方法不同,Pool是通过apply_async(func,args=(args))方法创建进程,一个进程池中能同时运行的任务数是机器上CPU核的总数量n_kernel,如果创建的子进程数大于n_kernel,则同时执行n_kernel个进程,这n_kernel中某个进程完成之后才会启动下一个进程。
# coding=utf-8
from multiprocessing import Pool
import os, time
def long_time_task(name):
print 'Run task {0} ({1})'.format(name, os.getpid())
start = time.time()
time.sleep(3)
end = time.time()
print 'Task {0} runs {1:.2f} seconds.'.format(name, end - start)
if __name__ == '__main__':
print 'Parent process ({0})'.format(os.getpid)
p = Pool()
for i in range(12):
p.apply_async(long_time_task, args=(i,))
print 'Waiting for all subprocesses done...'
p.close()
p.join()
print 'All subprocesses done.'
运行结果:
Parent process (
Waiting for all subprocesses done...
Run task 0 (3424)
Run task 1 (3423)
Task 0 runs 3.00 seconds.
Task 1 runs 3.00 seconds.
Run task 2 (3424)
Run task 3 (3423)
Task 2 runs 3.00 seconds.
Run task 4 (3424)
Task 3 runs 3.00 seconds.
Run task 5 (3423)
Task 4 runs 3.00 seconds.
Run task 6 (3424)
Task 5 runs 3.00 seconds.
Run task 7 (3423)
Task 6 runs 3.00 seconds.
Run task 8 (3424)
Task 7 runs 3.00 seconds.
Run task 9 (3423)
Task 8 runs 3.00 seconds.
Run task 10 (3424)
Task 9 runs 3.00 seconds.
Run task 11 (3423)
Task 10 runs 3.00 seconds.
Task 11 runs 3.00 seconds.
All subprocesses done.
三 多个子进程间的通信
多个子进程间的通信要用到multiprocessing.Queue,Queue的特性是它是一个消息队列。比如有以下的需求,一个子进程向队列中写数据,另外一个进程从队列中取数据的例子:
# coding=utf-8
from multiprocessing import Process, Queue
import os, time, random
'''
实现进程间通信
'''
def write(q):
for value in ['A12', 'B34', 'C56']:
print 'Put {0} to queue...'.format(value)
q.put(value)
time.sleep(random.random())
def read(q):
while True:
if not q.empty():
value = q.get(True)
print 'Get {0} from queue.'.format(value)
time.sleep(random.random())
else:
break
if __name__ == '__main__':
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
pw.start()
pw.join()
pr.start()
pr.join()
结果:
Put A12 to queue...
Put B34 to queue...
Put C56 to queue...
Get A12 from queue.
Get B34 from queue.
Get C56 from queue.
Queue使用方法: