python中Multiprocessing的使用
python中Multiprocessing的使用
环境
python——>3.8
windows
Process
简要
多进程的使用在python中是必要的,原因在于python的解释器。python的解释器是GIL
,全称是global interpreter lock
-- 全局解释器锁。CPython解释器所采用的一种机制,它确保同一时刻只有一个线程在执行 Python代码。所以为了避免这种影响,通常我们可以创建多进程,用子进程来代替线程。
详细介绍
构造
class multiprocessing.Process
(group=None, target=None, name=None, args=(), kwargs={}, ***, daemon=None)
- group:默认必须为None。
- target:要执行的方法名称。
- name:进程名称。
- args/kwargs:传入方法需要的参数。
- daemon:守护进程,当进程退出时,守护进程的所有子进程也将终止
那么上述是构造类的各个参数的详情,构造之后我们还需要知道运行实例的一些方法
方法
- run():表示进程活动的方法target。
- start():启动进程。
- join([timeout]):进程终止,timeout为可选参数,为阻塞时间。
- terminate():立即停止当前进程(不考虑当前进程是否完成)
- is_alive():用来返回当前进程是否运行
创建子进程
直接使用Process
类创建子进程
from multiprocessing import Process
import os
def demo():
print('Parent Process ID: %d' %(os.getppid()))
print('Process ID: %d' %(os.getpid()))
if __name__ == '__main__':
p = Process(target=demo)
p.start()
p.join()
运行结果:
>python 1.py
Parent Process ID: 8428
Process ID: 5500
Pool
简要
进程池,这个主要是当需要的进程数量很多的时候采用到进程池来限制进程数量,从而不需要我们再去敲代码来限制进程的数量,当进程少时,我们直接用Process
就可以了
详细介绍
构造
class multiprocessing.pool.Pool
([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])
- processes :使用的工作进程的数目,如果processes是None,则使用 os.cpu_count()返回的值。
- initializer: 如果initializer不是None,那么每一个工作进程将会再启动时调用initializer(*initargs)。
- maxtasksperchild 是一个工作进程在它退出或被一个新的工作进程代替之前能完成的任务数量,为了释放未使用的资源。默认的 maxtasksperchild 是
None
,意味着工作进程和进程池Pool生命周期相同。 - context 可被用于指定启动的工作进程的上下文。通常一个进程池是使用函数
multiprocessing.Pool()
或者一个上下文对象的Pool()
方法创建的。在这两种情况下, context 都是适当设置的。
方法
- apply(func[, args[, kwds]]) :返回结果前阻塞
- apply_async(func[, args[, kwds[, callback]]]):回调函数应该立即执行完成,否则会阻塞负责处理结果的线程。
- close():阻止后续任务提交到进程池,当所有任务执行完成后,工作进程会退出。
- terminate():不必等待未完成的任务,立即停止工作进程。当进程池对象被垃圾回收时, 会立即调用
terminate()
- join():等待工作进程结束。调用
join()
前必须先调用close()
或者terminate()
- map(func, iterable[, chunksize]):这个方法会将可迭代对象分割为许多块,然后提交给进程池。可以将 chunksize 设置为一个正整数从而(近似)指定每个块的大小可以。
- imap(func, iterable[, chunksize]):
map()
的延迟使用版本,如果 chunksize 是1
, 那么imap()
方法所返回的迭代器的next()
方法拥有一个可选的 timeout 参数: 如果无法在 timeout 秒内执行得到结果,则next(timeout)
会抛出multiprocessing.TimeoutError
异常。
用法
调用map
from multiprocessing import Pool
def demo(flag):
print('www.jlx-love.com flag %d' %flag)
if __name__=="__main__":
flag = [1, 2, 3, 4, 5, 6, 7, 8, 9]
pool = Pool(processes=3)
pool.map(demo, flag)
pool.close()
pool.join()
运行结果:
>python 1.py
www.jlx-love.com flag 1
www.jlx-love.com flag 2
www.jlx-love.com flag 3
www.jlx-love.com flag 4
www.jlx-love.com flag 5
www.jlx-love.com flag 6
www.jlx-love.com flag 7
www.jlx-love.com flag 8
www.jlx-love.com flag 9
这里我设置进程池最大进程数是3,当然也可以设置成别的,然后我们采用map()
方法传递可迭代对象,记住,对象必须是可迭代的。然后关闭进程池任务,调用完close()
停止进程池继续接收任务后再调用join()
等待工作进程结束
调用apply()
from multiprocessing import Pool
import time
def demo(flag):
print('www.jlx-love.com flag %d' %flag)
if __name__=="__main__":
start = time.time()
pool = Pool(processes=5)
for flag in range(50):
pool.apply(demo, args=(flag, ))
print('I am a flag')
pool.close()
pool.join()
end = time.time()
print('用时:%f' %(end - start))
运行结果:
www.jlx-love.com flag 0
.
.
.
.
www.jlx-love.com flag 47
www.jlx-love.com flag 48
www.jlx-love.com flag 49
I am a flag
用时:0.339805
调用apply_async()
from multiprocessing import Pool
import time
def demo(flag):
print('www.jlx-love.com flag %d' %flag)
if __name__=="__main__":
start = time.time()
pool = Pool(processes=5)
for flag in range(50):
pool.apply_async(demo, args=(flag, ))
print('I am a flag')
pool.close()
pool.join()
end = time.time()
print('用时:%f' %(end - start))
运行结果:
I am a flag
www.jlx-love.com flag 0
.
.
.
.
www.jlx-love.com flag 48
www.jlx-love.com flag 49
用时:0.342791
不知道你有没有发现上面两个方法结果的不同?就是输出I am a flag
位置不同,apply()
是等进程池中的子进程全部完成后才输出内容,而apply_async()
则是当执行完for循环步骤后即输出内容,所以我们看到了输出内容的位置不同之处。所以有此结论:
apply()---------------------->同步(阻塞)
apply_async()---------------->异步(非阻塞)