- 多进程: multiprocessing 模块
p = multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, * , daemon=None)
daemon 是守护进程,如果 daemon 为 True,那么当主进程结束时,无论子进程是否执行完成都会被杀死。
用 Process 创建好进程后,需要启动进程 p.start()
p.join() 会阻塞当前进程,直到子进程执行完毕后继续执行
# 发送十封邮件
import time
import random
from multiprocessing import Process
def func(index):
time.sleep(random.randint(1, 3))
print('第%s封邮件发送完毕' % index)
if __name__ == '__main__':
p_lst = []
for i in range(10):
p = Process(target=func, args=(i,))
p.start() # 先让所有子进程都启动
p_lst.append(p)
for p in p_lst: # 再进行join阻塞
p.join()
print('10封邮件全部发送完毕')
对于多个子进程的情形,更简洁的方法是采用进程池:
multiprocessing.Pool(processes=None, initializer=None, initargs=(), maxtasksperchild=None)
processes :进程数量,默认使用 os.cpu_count(),主机最大 CPU 数量
initializer :可以为空,在 每一个 进程开始时会调用 initializer(*initargs), 比如在初始化的时候建立连接,连接重用。
maxtasksperchild:用户设置每个子进程执行多少个任务后重启。防止内存溢出、资源未释放等问题,默认不重启。 线程池 无此参数。
进程池(pool)中创建子进程的方法:
- 普通调用:
pool.apply(func, args=(), kwds={}, callback=None, error_callback=None)
apply 对应的子进程 排队执行,实际非并行,按顺序执行每个子进程
pool.apply_async(func, args=(), kwds={})
apply_async 对应的每个子进程异步执行
pool.close() 关闭进程池,关闭后不能往 pool 中增加新的子进程,然后可以调用 join() 函数 等待已有子进程执行完毕
pool.join() 等待进程池中的子进程执行完毕,需要在 close() 函数后调用。
from multiprocessing import Pool, TimeoutError
import time
def f(x):
time.sleep(x)
return x
if __name__ == '__main__':
# start 4 worker processes
start = time.time()
with Pool(processes=4) as pool:
result = [pool.apply(f, (x, )) for x in range(4)]
print(result)
print(time.time() - start)
>>>
[0, 1, 2, 3]
6.39384913444519
from multiprocessing import Pool, TimeoutError
import time
def f(x):
time.sleep(x)
return x
if __name__ == '__main__':
# start 4 worker processes
start = time.time()
with Pool(processes=4) as pool:
result = [pool.apply_async(f, (x, )) for x in range(4)]
print([res.get() for res in result])
print(time.time() - start)
>>>
[0, 1, 2, 3]
3.37103271484375
- 如果子进程有返回值,且返回值需要集中处理,可以采用 map 方式(子进程活动只允许 1 个参数)
pool.map(func, iterable, chunksize=None)
将iterable 的每个元素作为参数,应用func 函数。 这里是子进程阻塞进行。
pool.map_async(func, iterable, chunksize=None, callback=None, error_callback=None)
异步执行,返回 MapResult 实例 (有 get() 方法,获取结果)
from multiprocessing import Pool, TimeoutError
import time
def f(x):
time.sleep(x)
return x
if __name__ == '__main__':
# start 4 worker processes
start = time.time()
with Pool(processes=4) as pool:
result = pool.map(f, range(10))
print(result)
print(time.time() - start)
>>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
15.37588882446289
from multiprocessing import Pool, TimeoutError
import time
def f(x):
time.sleep(x)
return x
if __name__ == '__main__':
# start 4 worker processes
start = time.time()
with Pool(processes=4) as pool:
result = pool.map_async(f, range(10))
print([res for res in result.get()])
print(time.time() - start)
>>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
15.358932256698608
- 如果内存不够用,可以采用 imap 迭代器方式:
pool.imap(func, iterable, chunksize=1)
pool.map 的迭代器版本,返回迭代器实例,pool.imap 远慢于 pool.map,但是对内存需求非常小
pool.imap_unordered(func, iterable, chunksize=1)
pool.imap() 的无序版本(不会按照调用顺序返回,而是按照结束顺序返回),返回迭代器实例。
from multiprocessing import Pool, TimeoutError
import time
def f(x):
time.sleep(x)
return x
if __name__ == '__main__':
# start 4 worker processes
start = time.time()
with Pool(processes=4) as pool:
result = pool.imap_unordered(f, range(10))
print([res for res in result])
print(time.time() - start)
>>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
15.357933759689331
- 如果子进程活动具有多个参数,则不能直接使用map方式,需采用 starmap 方式:
pool.starmap(func, iterable, chunksize=None)
类似 pool.map(),但是 func 允许包含多个参数,iterable 的每个 元素也是 iterable(其每个元素作为func的参数),返回结果组成的list。
pool.starmap_async(func, iterable, chunksize=None, callback=None, error_callback=None)
pool.starmap() 的异步版本,返回 MapResult 实例。
from multiprocessing import Pool, TimeoutError
import time
def f(x, y):
time.sleep(x)
return y
if __name__ == '__main__':
# start 4 worker processes
start = time.time()
with Pool(processes=4) as pool:
result = pool.starmap_async(f, ((i, i) for i in range(10)))
print([res for res in result.get()])
print(time.time() - start)
>>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
15.355940103530884
参考资料:
https://iyaozhen.com/multiprocessing-and-threading-pool.html
https://www.cnblogs.com/Zzbj/p/9677645.html
https://zhuanlan.zhihu.com/p/46798399