1.fork进程:
(1)在windows系统中不可以用fork来创建进程,linux可以,但是创建大量进程使用很不方便。
2.Process进程:
1 #多任务,进程 2 from multiprocessing import Process 3 import time 4 def test(): 5 while True: 6 print("-------test------") 7 time.sleep(1) 8 def test1(): 9 while True: 10 print('------test2') 11 time.sleep(2) 12 13 def main(): 14 p1= Process(target=test) #开启一个进程 15 p1.start()#让这个进程开始执行test函数里面的代码 16 p2=Process(target=test1) 17 p2.start() 18 p1.join() #等待 就是join会让子进程进行完(完成),才会执行主进程(join还可以带参数 等待多长时间) 19 print('---主进程----') 20 if __name__ == '__main__': 21 main()
windows下运行结果:
1 -------test------ 2 ------test2 3 -------test------ 4 -------test------ 5 ------test2 6 -------test------ 7 -------test------ 8 ------test2 9 -------test------ 10 -------test------ 11 ------test2 12 -------test------
说明:
(1)if __name__ == '__main__':
在windows环境下创建进程及相关的可执行代码必须放在if __name__ == '__main__':下,否则会报错;但是linux系统没有这个问题。
三:进程池Pool
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态生成多个进程,但如果是成百上千个目标时,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块中提供的Pool .
初始化Pool时,可以指定一个最大的进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行。 1 from multiprocessing import Pool
2 def worker(): 3 print('-----这里是要执行的任务') 4 def test(): 5 po = Pool(3) # 在这里创建线程池,3 是代表这个线程池中线程最大数量是3 6 po.apply_async(worker()) # 向线程中添加任务,(就是开辟线程)(apply_async()是非堵塞的方式){po.apply(worker)这个是堵塞的方式}
7 po.close() #关闭线程池,相当于不在添加新任务了 8 po.join() #等待所有的子进程执行完成,必须放在close之后(主进程创建/添加任务后,主进程 默认不会等待进程池中的任务完成后才结束,而是 当主进程做完任务后 立刻结束,,,如果这个地方没有join,会导致进程池中的任务不会执行) 9 10 if __name__ =='__main__': 11 test()
运行结果:
1 -----这里是要执行的任务
(1)Pool进程也一样,在windows环境下相关的可执行代码必须放置在if __name__ == '__main__'下。
四:进程间通信:Queue
proccess之间有时需要通信,操作系统提供了很多机制来实现进程间的通信。
可以使用multiprocessing模块中的Queue实现多进程之间的数据传递,Queue本身就是一个消息列队程序
1 >>> q = Queue(3)# 初始化一个Queue对象,最大可接收三条put消息 2 >>> q.qsize() #返回当前队列包含的消息数量 3 0 4 >>> q.put('第一条消息')#向当前队列添加数据 5 >>> q.qsize() 6 1 7 >>> q.put('第二条消息') 8 >>> q.put('第三条消息') 9 >>> q.qsize() 10 3 11 >>> q.get()# 从队列里取出数据,(先进先出) 12 '第一条消息' 13 >>> q.qsize() 14 2 15 >>> q.get() 16 '第二条消息' 17 >>> q.qsize() 18 1 19 >>> q.get() 20 '第三条消息' 21 >>> q.qsize() 22 0 23 >>> q.empty()#判断当前队列是否为空,为空则返回True,否则返回False 24 True 25 >>> q.full()#判断当前队列是否是满的,满的则返回True,否则返回False 26 False 27 >>> q.put('再添加一条消息') 28 >>> q.get() #get()从队列里取数据如果有数据就会直接取出来,否则会一直等待 29 '再添加一条消息' 30 >>> q.get_nowait()#从队列里取数据如果没有数据则不以等待,直接会以异常提示 31 Traceback (most recent call last): 32 File "<pyshell#33>", line 1, in <module> 33 q.get_nowait()#从队列里取数据如果没有数据则不以等待,直接会以异常提示 34 File "E:\python\lib\multiprocessing\queues.py", line 126, in get_nowait 35 return self.get(False) 36 File "E:\python\lib\multiprocessing\queues.py", line 107, in get 37 raise Empty 38 queue.Empty 39 >>>
Process创建进程之间的通信
示例代码:
1 #进程间的通信,Process版的 2 from multiprocessing import Queue 3 from multiprocessing import Process 4 def writer(a): 5 print('向队列中添加数据') 6 x = a.put('写入的数据') 7 def read(b): 8 print('读取队列中的数据') 9 if b.empty()== False: 10 y =b.get() 11 print(y) 12 else: 13 print('没有数据') 14 if __name__ == '__main__': 15 q = Queue() # 使用Queue()来初始化 16 p1= Process(target=writer,args=(q,)) 17 p2=Process(target=read,args=(q,)) 18 p1.start() 19 p2.start()
运行结果:
1 向队列中添加数据 2 读取队列中的数据 3 写入的数据
Pool进程池创建进程之间的通信
注意:Pool进程池创建的进程之间通信,需要导入Manager
示例代码:
1 #进程间的通信 Pool 2 from multiprocessing import Manager 3 from multiprocessing import Pool 4 def writer(a): 5 print('向队列中添加数据') 6 a.put('写入的数据') 7 def read(b): 8 print('读取队列中的数据') 9 if b.empty()== False: 10 y =b.get() 11 print(y) 12 else: 13 print('没有数据') 14 def test(): 15 q =Manager().Queue() # 使用Manager中的Queue()来初始化 16 p=Pool(3) 17 p.apply_async(writer,(q,)) 18 p.apply_async(read,(q,)) 19 p.close() 20 p.join() 21 if __name__ =='__main__': 22 test()
运行结果:
1 向队列中添加数据 2 读取队列中的数据 3 写入的数据
一个多进程和进程通信的实例代码:
实现多进程拷贝文件夹
1 import os 2 from multiprocessing import Manager,Pool 3 import time 4 5 def copyFileTask(name,oldFolderName,newFolderName,qu): 6 '拷贝文件操作' 7 fr = open(oldFolderName+'/'+name,'r',encoding='utf-8') 8 content = fr.read(1024) 9 fw = open(newFolderName+'/'+name,'w',encoding='utf-8') 10 fw.write(content) 11 fr.close() 12 fw.close() 13 qu.put(name) 14 15 def main(): 16 startTime=time.time() 17 oldFolderName = input("请输入你要拷贝的文件夹名称:") #获取要拷贝的文件夹名称 18 #读取文件夹中所有的文件名 19 listNames = os.listdir(oldFolderName) 20 #创建一个新的文件夹 21 newFolderName = oldFolderName+'复件' 22 os.mkdir(newFolderName) 23 #创建进程池,实现多任务 24 po = Pool(5) 25 qu=Manager().Queue() 26 #遍历listNames,获取每一个文件的名称 27 for name in listNames: 28 po.apply_async(copyFileTask,args=(name,oldFolderName,newFolderName,qu)) 29 30 num = 0 31 allNum= len(listNames) 32 while num < allNum: 33 qu.get() 34 print() 35 num += 1 36 copyRote= num/allNum # 求出拷贝的进度条 37 print('\copy的进度是:%.2f%%'%(copyRote*100),end='') 38 print('') 39 overTime=time.time() 40 allTime=overTime - startTime 41 print(allTime) 42 if __name__ == '__main__': 43 main()
运行结果:
1 请输入你要拷贝的文件夹名称:aaaa 2 3 \copy的进度是:4.35% 4 3.575204372406006 5 6 \copy的进度是:8.70% 7 3.575204372406006 8 9 \copy的进度是:13.04% 10 3.579204559326172 11 12 \copy的进度是:17.39% 13 3.580204725265503 14 15 \copy的进度是:21.74% 16 3.581204652786255 17 18 \copy的进度是:26.09% 19 3.585205078125 20 21 \copy的进度是:30.43% 22 3.585205078125 23 24 \copy的进度是:34.78% 25 3.588205099105835 26 27 \copy的进度是:39.13% 28 3.588205099105835 29 30 \copy的进度是:43.48% 31 3.589205265045166 32 33 \copy的进度是:47.83% 34 3.593205451965332 35 36 \copy的进度是:52.17% 37 3.595205307006836 38 39 \copy的进度是:56.52% 40 3.595205307006836 41 42 \copy的进度是:60.87% 43 3.596205472946167 44 45 \copy的进度是:65.22% 46 3.600205898284912 47 48 \copy的进度是:69.57% 49 3.601206064224243 50 51 \copy的进度是:73.91% 52 3.602205991744995 53 54 \copy的进度是:78.26% 55 3.603205919265747 56 57 \copy的进度是:82.61% 58 3.60520601272583 59 60 \copy的进度是:86.96% 61 3.609206199645996 62 63 \copy的进度是:91.30% 64 3.610206365585327 65 66 \copy的进度是:95.65% 67 3.6122066974639893 68 69 \copy的进度是:100.00% 70 3.613206624984741