在unix/linux操作系统中,提供了一个fork()系统函数,它非常特殊。
#只能在Linux和unix系统下运行
import os
pid=os.fork()
if pid<0:
print('fork失败')
elif pid==0: #子进程运行
print('子进程%s父进程%s'%(os.getpid(),os.getppid()))
else:#父进程运行
print('父进程%s子进程%s' % (os.getpid(), pid))
print('父子进程都可以执行')
由于py是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块提供了一个Process类来代表一个进程对象。
该句执行时才是正常的创建子进程,而不是Process时创建
父进程阻塞等待子进程执行完毕,timeout设置最长的阻塞时间,如果操作该时间还没有子进程退出,则不在继续等待。
from multiprocessing import Process
import os
#子进程执行代码
def run(name):
print('子进程运行中,name=%s,pid=%d'%(name,os.getpid()))
if __name__=='__main__':
print('父进程%d'%os.getpid())
#target为子进程需要执行的函数
p=Process(target=run,args=('test',))
print('子进程将执行')
p.start()
#等待子进程执行完父进程继续执行
p.join()
print('子进程执行结束')
from multiprocessing import Process
import os
#子进程执行代码
def run(name):
print('子进程运行中,name=%s,pid=%d'%(name,os.getpid()))
if __name__=='__main__':
print('父进程%d'%os.getpid())
p=Process(target=run,kwargs={'name':'test',})
print('子进程将执行')
#守护父进程,让子进程不在执行了。
p.daemon=True
p.start()
#等待子进程执行完父进程继续执行
#p.join()
print('子进程执行结束')
创建新的进程还可以使用类的方式,可以自定义一个类,继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象。我们需要做的就是重写run()方法,这点和java多线程的创建方式很像。
from multiprocessing import Process
import os
import time
class Process_Test(Process):
def __init__(self,interval):
Process.__init__(self)
self.interval=interval
#重写run方法
def run(self):
print('子进程%d,父进程%d'%(os.getpid(),os.getppid()))
t_start=time.time()
time.sleep(self.interval)
t_stop=time.time()
print('%s执行结束,耗时%0.2f'%(os.getpid(),t_stop-t_start))
if __name__=='__main__':
p=Process_Test(2)
p.start()
p.join()
print('主进程%s'%os.getpid())
'''
子进程1448,父进程11976
1448执行结束,耗时2.00
主进程11976
'''
当需要创建的子进程数量不多时,可以利用上面的Process动态生成多个进程,如果创建的进程多,可以使用multiprocessing模块提供的Pool方法。
初始化进程池Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池子没有满,那么就创建一个新的进程来执行该请求。如果池中进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行。
通过下面例子我们可以看出,当创建出三个进程后,只有其中一个进程执行完毕,才会在创建一个新的进程。
from multiprocessing import Pool
import os,time,random
def worker(msg):
t_start=time.time()
print('%s开始执行,进程号%d'%(msg,os.getpid()))
time.sleep(random.random()*2)
t_stop=time.time()
print(msg,'执行完毕,耗时%0.2f'%(t_stop-t_start))
if __name__=='__main__':
pool = Pool(3) # 创建一个进程池,最大进程数为3
for i in range(10):
# 每次循环将会用空闲出来的子进程去调用目标
# 异步
pool.apply_async(worker, (i,))
print('--start--')
pool.close() # 关闭进程池
pool.join() # 等待进程池中所有子进程执行完毕,必须放在close()之后
print('--end--')
'''
#异步执行结果
--start--
0开始执行,进程号9244
1开始执行,进程号12652
2开始执行,进程号732
2 执行完毕,耗时0.26
3开始执行,进程号732
3 执行完毕,耗时0.35
4开始执行,进程号732
0 执行完毕,耗时0.80
5开始执行,进程号9244
1 执行完毕,耗时0.80
6开始执行,进程号12652
4 执行完毕,耗时0.25
7开始执行,进程号732
7 执行完毕,耗时0.40
8开始执行,进程号732
6 执行完毕,耗时1.74
9开始执行,进程号12652
8 执行完毕,耗时1.45
5 执行完毕,耗时1.99
9 执行完毕,耗时0.35
--end--
#同步执行结果
0开始执行,进程号6360
0 执行完毕,耗时0.47
1开始执行,进程号12684
1 执行完毕,耗时1.99
2开始执行,进程号8780
2 执行完毕,耗时1.17
3开始执行,进程号6360
3 执行完毕,耗时0.23
4开始执行,进程号12684
4 执行完毕,耗时1.01
5开始执行,进程号8780
5 执行完毕,耗时1.69
6开始执行,进程号6360
6 执行完毕,耗时0.31
7开始执行,进程号12684
7 执行完毕,耗时0.86
8开始执行,进程号8780
8 执行完毕,耗时0.66
9开始执行,进程号6360
9 执行完毕,耗时1.88
--start--
--end--
'''
进程池使用消息队列的类和Process类使用的消息队列的类是不同的。
from multiprocessing import Process,Pool,Queue
import os,time,random
def write(q):
for item in 'ABC':
print('写消息%s'%item)
q.put(item)
time.sleep(random.random())
def read(q):
while True:
if not q.empty():
item=q.get()
print('读消息%s'%item)
time.sleep(random.random())
else:
break
if __name__=='__main__':
q=Queue()
pw=Process(target=write,args=(q,))
pw.start()
pw.join()
pr=Process(target=read,args=(q,))
pr.start()
pr.join()
'''
写消息A
写消息B
写消息C
读消息A
读消息B
读消息C
'''
from multiprocessing import Manager,Pool
import os,time,random
def write(q):
for item in 'ABC':
print('写消息%s'%item)
q.put(item)
time.sleep(random.random())
def read(q):
while True:
if not q.empty():
item=q.get()
print('读消息%s'%item)
time.sleep(random.random())
else:
break
if __name__=='__main__':
#进程池使用消息队列,消息队列只能使用这一种
q=Manager().Queue()
pool=Pool(3)
#创建写进程
pool.apply(write,(q,))
#创建读进程
pool.apply(read,(q,))
pool.close()
pool.join()
'''
写消息A
写消息B
写消息C
读消息A
读消息B
读消息C
'''