1. 前言
在Python编程过程中,经常需要多进程或多线程来实现并发。与多线程相比,多进程在Python中更加强大和安全,可以通过操作系统的进程管理实现运算分离、资源隔离等,从而提高程序的稳定性。
Python自带了multiprocessing模块,使得并行编程更加简洁。
2. multiprocessing模块概述
Python的multiprocessing模块提供了一个 Process 类来代表一个进程对象。
2.1 Process类
每个进程都被封装在一个 Process 实例中。Process 类具有很多方法和属性。如果要定义一个新的进程,必须继承 Process 并实现其 run() 方法。其中run() 方法定义了进程的活动,它是一个必须实现的方法。
from multiprocessing import Process
def f(name):
print('hello', name)
if __name__ == '__main__':
p = Process(target=f, args=('Bob',))
p.start()
p.join()
注意:在Windows系统下,由于没有fork调用,可以参考如下方法实现进程的创建:
from multiprocessing import Process, Value, Array
def f(n, a):
n.value = 3.1415927
for i in range(len(a)):
a[i] *= 2
if __name__ == '__main__':
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target=f, args=(num, arr))
p.start()
p.join()
print(num.value)
print(arr[:]
2.2 Pool类
Pool类提供了一个process类的简单方式,来批处理任务3。
from multiprocessing import Pool
import time
def f(x):
time.sleep(2)
return x*x
if __name__ == '__main__':
with Pool(5) as p:
print(p.map(f, [1, 2, 3]))
3. multiprocessing模块使用示例
下面以一个简单的示例演示如何使用multiprocessing模块实现多进程管理。
需求:计算0~10000之间的素数。采用多进程方式,将数字拆分成两个部分,每部分交由一个进程计算素数,最后将结果合并。
3.1 单进程版代码
首先是单进程版的代码,使用循环计算从0到10000之间的素数:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import math
import time
def is_prime(number):
"""
判断一个数是否为素数。
:param number: 待判断的数。
:return: 如果number是素数,返回True;否则,返回False。
"""
for i in range(2, int(math.sqrt(number) + 1)):
if number % i == 0:
return False
return True
if __name__ == '__main__':
start = time.time()
primes = []
for number in range(1, 10000):
if is_prime(number):
primes.append(number)
print(len(primes))
end = time.time()
print('Elapsed time: {} s'.format(end - start))
注意:如果在Windows下运行上面的代码会出现如下问题:
AttributeError: module 'math' has no attribute 'sqrt'
这是因为Windows下使用的Python解释器是通过freeglut库实现的,它没有math库的内容。所以,如果你在Windows下使用Python,只需要改变头文件的引入方式即可。将代码中的:
import math
改成:
from math import sqrt
然后,将用到`sqrt()`的代码修改成:
for i in range(2, int(sqrt(number) + 1)):
if number % i == 0:
return False
3.2 多进程版代码
现在,我们来看看如何使用multiprocessing模块,将程序改为支持多进程计算。
将一个计算任务划分成若干份,每部分采用不同的进程计算,最后再将结果合并。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import math
import multiprocessing
import time
def is_prime(number):
"""
判断一个数是否为素数。
:param number: 待判断的数。
:return: 如果number是素数,返回True;否则,返回False。
"""
for i in range(2, int(math.sqrt(number) + 1)):
if number % i == 0:
return False
return True
def calc(start, end):
primes = []
for number in range(start, end):
if is_prime(number):
primes.append(number)
return primes
if __name__ == '__main__':
start = time.time()
pool = multiprocessing.Pool(processes=4)
results = []
for i in range(4):
start_num = i * 2500
end_num = start_num + 2500
results.append(pool.apply_async(calc, (start_num, end_num)))
pool.close()
pool.join()
primes = []
for result in results:
primes += result.get()
print(len(primes))
end = time.time()
print('Elapsed time: {} s'.format(end - start))
在这个代码中,我们首先创建了一个包含4个进程的进程池,然后将计算任务0~10000划分成了$4\times2500$个部分。接着将运算任务交由进程池的4个进程并行计算。最后,将每个进程的结果合并成最终结果输出。
可以看出,多进程版的代码执行效率要高于单进程版,这是因为多进程可以并行计算,充分利用了系统资源。
4. 总结
本文介绍了如何使用Python的multiprocessing模块实现多进程管理,以及如何将单进程程序改为支持多进程计算的程序。通过这些示例,我们可以学习到如何使用Python的multiprocessing模块。同时,也可以在实际应用中,通过使用多进程技术来提高程序的执行效率。