多进程
文章目录
先来个辅助函数
from multiprocessing import Pool
import time, os, random
from functools import wraps
def timethis(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return res
return wrapper
系统级别的
import os
# os.getpid() : 获取自己的集成ID
# os.getppid() : 获取父进程的ID
print(f'父进程的ID:{os.getppid()}')
print(f'自己的ID: {os.getpid()}')
pid = os.fork()
print(os.getpid())
进程这样写
import os
from multiprocessing import Process
def run():
print('child', os.getpid())
if __name__ == '__main__':
print(os.getpid())
p = Process(target=run)
p.start()
p.join()
Lock – 同时只能有一个访问我!
from multiprocessing import Process, Lock
import time
def run(lock, title):
time.sleep(1)
print(title)
with lock:
time.sleep(1)
print(title)
if __name__ == '__main__':
lock = Lock()
for i in range(10):
Process(target=run, args=(lock, i)).start()
Pool – 进程很多的话,应该用进程池
调用
join()
方法会等待所有子进程执行完毕,调用join()
之前必须先调用close()
,调用close()
之后就不能继续添加新的Process
了
@timethis
def main():
print(os.getpid(),'main start ===============')
p = Pool()
for i in range(8):
p.apply_async(run)
p.close()
p.join()
print(os.getpid(), 'main end ==================')
进程池还有种写法
with Pool(processes=28) as p:
res = p.map(f, range(1, 20))
print(res)
subprocess – 但很多时候,调用的是外部进程
import subprocess
r = subprocess.call(['nslookup', 'www.python.org'])
print(r)
# 如果需要交互 , 通过communicate()方法输入
p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'set q=mx\npython.org\nexit\n')
print(output.decode('utf8'))
Queue – 进程通信,用队列来搞一搞
from multiprocessing import Process, Queue
import os, random, time
def fwrite(q):
print(os.getpid(), 'task runing ')
products = list('qwertyuiopasdfghjklzxcvbnm')
for i in range(3):
time.sleep(1)
v = random.choice(products)
q.put(v)
print(os.getpid(), f'write {v}')
def fread(q):
print(os.getpid(), 'read running')
while True:
value = q.get(True)
print(os.getpid(), f'read {value}')
if __name__ == '__main__':
print(os.getpid(), '**' * 20)
q = Queue()
pw = Process(target=fwrite, args=(q,))
pr = Process(target=fread, args=(q,))
pw.start()
pr.start()
print('我早就执行了么?')
# 下面这两句很精髓
# 如果没有下面两句,主进程就一路执行到底。
# 如果没有pw.join(), 主进程直接执行 pr.terminate() 干掉了读进程。
# pw.join()把主进程阻塞在这里,写完之后,主进程继续。
pw.join()
pr.terminate()
# time.sleep(4)
# print('主进程休息了4秒')
# print(pr.is_alive())
# print(pw.is_alive())
死循环 子进程 永生?
子进程 设置为 daemon 进程
pr = Process(target=fread, args=(q,))
# 注意成死掉之后,daemon进程也就跟着死了。
pr.daemon = True
pr.start()
# 如果在 daemon 基础上加上这个,那么死循环的 子进程 又能永生了。
# pr.join()
强制终结子进程
pr.terminate()
最后再明确下
-
主进程运行结束了,子进程还在运行。 子进程 会在 父进程 的尸体上 运行到结束。
- 当然,主进程调用 子进程的terminate() 会强行带走 子进程
- 或者,子进程设置为 daemon , 那么就会随着主进程死去。
-
Join()的意思是:“主进程停下,等我执行完,你再继续” 。
子进程 join 函数会阻塞主进程,让主进程在这里停下,等自己结束再继续运行。
-
Pool() 的 apply是同步的,大家一个挨一个执行,先来后到,禁止插队!
apply_async 是异步的。只要CPU空闲了,大家快去抢CPU啊!手快有手慢无!