多进程 multiprocessing模块
multiprocessing模块提供了一个Process类来代表一个进程对象
from multiprocessing import Processimport os def run_proc(name): # 子进程要执行的函数 print('Run child process %s (%s)...' % (name, os.getpid())) # os.getpid()表示获得当前进程的pid if __name__=='__main__': print('Parent process %s.' % os.getpid()) # 打印父进程的pid p = Process(target=run_proc, args=('test',)) # 创建进程对象,参数结构和多线程一样 print('Child process will start.') p.start() # 启动子进程 p.join() # 阻塞等待子进程执行完毕 print('Child process end.')
并且在使用多进程的时候,最好是创建多少个进程?:和CPU核数相等
默认的进程之间相互是独立,如果想让进程之间数据共享,就得有个特殊的数据结构,这个数据结构就可以理解为他有穿墙的功能
如果你能穿墙的话两边就都可以使用了使用了3种方法默认的进程无法进行数据共享
import multiprocessingimport timedef func(msg): for i in range(4): print(msg) time.sleep(1)if __name__ == '__main__': p = multiprocessing.Process(target=func, args=("hello",)) p.start() p.join() print("have done")
使用特殊的数据类型,来进行穿墙:
默认的进程之间相互是独立,如果想让进程之间数据共享,就得有个特殊的数据结构,这个数据结构就可以理解为他有穿墙的功能如果你能穿墙的话两边就都可以使用了使用了3种方法第一种方法:#通过特殊的数据结构:数组(Array)from multiprocessing import Process,Array#创建一个只包含数字类型的数组(python中叫列表)#并且数组是不可变的,在C,或其他语言中,数组是不可变的,之后再python中数组(列表)是可以变得#当然其他语言中也提供可变的数组#在C语言中数组和字符串是一样的,如果定义一个列表,如果可以增加,那么我需要在你内存地址后面再开辟一块空间,那我给你预留多少呢?#在python中的list可能用链表来做的,我记录了你前面和后面是谁。 列表不是连续的,数组是连续的'''上面不是列表是“数组"数组是不可变的,附加内容是为了更好的理解数组!'''temp = Array('i', [11,22,33,44]) #这里的i是C语言中的数据结构,通过他来定义你要共享的内容的类型!点进去看~
def Foo(i): temp[i] = 100 + i for item in temp: print(i,'------->',item) for i in range(3): p = Process(target=Foo,args=(i,)) p.start()
##output
0 -------> 100
0 -------> 220 -------> 330 -------> 441 -------> 1001 -------> 1011 -------> 331 -------> 442 -------> 1002 -------> 1012 -------> 1022 -------> 44第二种方法:#方法二:manage.dict()共享数据
from multiprocessing import Process,Manager #这个特殊的数据类型Manager manage = Manager() dic = manage.dict() #这里调用的时候,使用字典,这个字典和咱们python使用方法是一样的! def Foo(i): dic[i] = 100+i print(dic.values()) for i in range(2): p = Process(target=Foo,args=(i,)) p.start() p.join() ##output
[100]
[100, 101]OK那么问题来了,既然进程之间可以进行共享数据,如果多个进程同时修改这个数据是不是就会造成脏数据?是不是就得需要锁!
进程的锁和线程的锁使用方式是非常一样的知识他们是用的类是在不同地方的
#!/usr/bin/env python# -*- coding:utf-8 -*-
from multiprocessing import Process, Array, RLock def Foo(lock,temp,i): """ 将第0个数加100 """ lock.acquire()#进程加锁,避免修改内存中相同数据被不同进程修改 temp[0] = 100+i for item in temp: print(i,'----->',item) lock.release() lock = RLock() temp = Array('i', [11, 22, 33, 44]) for i in range(5): p = Process(target=Foo,args=(lock,temp,i,)) p.start() ##output
0 -----> 100
0 -----> 220 -----> 330 -----> 441 -----> 1011 -----> 221 -----> 331 -----> 442 -----> 1022 -----> 222 -----> 332 -----> 443 -----> 1033 -----> 223 -----> 333 -----> 444 -----> 1044 -----> 224 -----> 334 -----> 44进程池
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:
- apply
- apply_async
#!/usr/bin/env python# -*- coding:utf-8 -*-# Author: Jason Wang#!/usr/bin/env python# -*- coding:utf-8 -*-from multiprocessing import Process,Poolimport timedef Foo(i): time.sleep(2) return i+100def Bar(arg): print(arg)pool = Pool(5) #创建一个进程池,初始化进程数为5# print(pool.apply(Foo,(1,)))#去进程池里去申请一个进程去执行Foo方法#101#print(pool.apply_async(func =Foo, args=(1,)).get())for i in range(10): pool.apply_async(func=Foo, args=(i,),callback=Bar)#为进程池中的进程注入func方法,这里有apply_async和apply两种方式,分别表示异步和同步print('end')pool.close()pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。##outputend100103102101104105108106107109'''apply 主动的去执行pool.apply_async(func=Foo, args=(i,),callback=Bar) 相当于异步,当申请一个线程之后,执行FOO方法就不管了,执行完之后就在执行callback ,当你执行完之后,在执行一个方法告诉我执行完了callback 有
close方法:说关闭进程池,至此,进程池中不在有进程可以接受任务。
terminate和join是一对方法,表示的内容截然相反,执行terminate是结束当前进程池中的所有进程,不管值没执行完。join方法是阻塞主进程,等待子进程执行完毕,再继续执行主进程。需要注意的是:这两个方法都必须在close方法之后执行。当然我们也可以不执行这两个方法,那么子进程和主进程就各自执行各自的,无论执行到哪里,子进程会随着主进程的结束而结束。。。
import timeimport multiprocessingdef func(msg): print(msg,'*** in func') time.sleep(3)if __name__ == "__main__": # pool = multiprocessing.Pool(processes=5) for i in range(3): print(i) pool.apply_async(func, ("hello %d" %(i), )) #pool.apply(func, ("hello %d" %(i), )) pool.close() #pool.terminate() #结束工作进程,不在处理未完成的任务 pool.join() #主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用 print("have done.")##output012hello 0 *** in funchello 1 *** in funchello 2 *** in funchave done.
获取进程池中进程的执行结果:
import multiprocessingimport timedef func(msg): print("msg : ", msg) time.sleep(3) print("end") return "multi_result : " + msgif __name__ == "__main__": pool = multiprocessing.Pool(processes=4) result = [] for i in range(3): msg = "hello %d" %(i) multi_result = pool.apply_async(func, (msg, )) result.append(multi_result) pool.close() pool.join() for res in result: print(res.get()) print("have done.")
参考文献:
python进程池:
python多进程的使用示例:
python的线程、进程和协程:
python的内存共享:
python的多进程编程: