Python 多进程multiprocessing
一、python多线程其实在底层来说只是单线程,因此python多线程也称为假线程,之所以用多线程的意义是因为线程不停的切换这样比串行还是要快很多。python多线程中只要涉及到io或者sleep就会切换线程。因此在io密集型的情况下可以用多线程。
二、python的多进程是直接调用原生进程,相当于直接调用硬件资源,可以实现多核的功能。
1、启动两个进程
1 #!/usr/bin/python 2 # -*- coding : utf-8 -*- 3 # 作者: Presley 4 # 时间: 2018-11-26 5 # 邮箱:1209989516@qq.com 6 # 这是我用来练习python多进程的测试脚本 7 8 from multiprocessing import Process 9 import time 10 11 def f(name): 12 time.sleep(2) 13 print("hello",name) 14 15 if __name__ == "__main__": 16 p = Process(target=f,args=("bob",)) 17 p2 = Process(target=f, args=("bob",)) 18 p.start() 19 p2.start() 20 p.join()
2、启动子进程
1 #!/usr/bin/python 2 # -*- coding : utf-8 -*- 3 # 作者: Presley 4 # 时间: 2018-11-26 5 # 邮箱:1209989516@qq.com 6 # 这是我用来练习python多进程的测试脚本 7 8 from multiprocessing import Process 9 import os 10 11 def info(title): 12 print(title) 13 print("module name:",__name__) 14 print("parent process:",os.getppid()) 15 print("process id:",os.getpid()) 16 print("\n\n") 17 18 def f(name): 19 info("\033[31;1mfunction f\033[0m") 20 print("hello",name) 21 22 if __name__ == "__main__": 23 info("\033[32;1mmain process line\033[0m") 24 p = Process(target=f,args=("bob",)) 25 p.start() 26 p.join()
执行结果:
C:\Users\wohaoshuai\AppData\Local\Programs\Python\Python36\python.exe E:/PythonLearn/day15/multiprocessing_learn.py main process line module name: __main__ parent process: 7308 #这是pycharm的进程号,也是主程序的主进程 process id: 9724 #这是主程序的进程 function f module name: __mp_main__ parent process: 9724 #这是子进程的父进程,也就是主程序的进程 process id: 3108 #这是子进程id
三、进程间通讯。
1、不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法:
a、Queues,使用方法跟threading里的queue差不多
1 #!/usr/bin/python 2 # -*- coding : utf-8 -*- 3 # 作者: Presley 4 # 时间: 2018-11-26 5 # 邮箱:1209989516@qq.com 6 # 这是我用来练习python多进程的测试脚本 7 8 from multiprocessing import Process,Queue 9 #Queue相当于给数据加了一把锁,只能按顺序排队取,在进程中使用Queue 10 11 def f(q): 12 q.put([42,None,"hello"]) 13 14 if __name__ == "__main__": 15 q = Queue() 16 p = Process(target=f,args=(q,)) #在子进程里put一个数据 17 p.start() 18 print(q.get()) #在父进程中get 19 p.join()
执行结果:
C:\Users\wohaoshuai\AppData\Local\Programs\Python\Python36\python.exe E:/PythonLearn/day15/multiprocessing_learn.py [42, None, 'hello']
b、多个进程向队列中写数据
#!/usr/bin/python # -*- coding : utf-8 -*- # 作者: Presley # 时间: 2018-11-26 # 邮箱:1209989516@qq.com # 这是我用来练习python多进程的测试脚本 from multiprocessing import Process,Queue #Queue相当于给数据加了一把锁,只能按顺序排队取,在进程中使用Queue def f(q): q.put([42,None,"hello"]) if __name__ == "__main__": q = Queue() p = Process(target=f,args=(q,)) #在子进程里put一个数据 p2 = Process(target=f, args=(q,)) # 在子进程里put一个数据 p.start() p2.start() print("from parent",q.get()) #在父进程中get print("from parent2",q.get()) print("from parent3",q.get())#因为已经被取完了所以没有了 p.join()
执行结果:
C:\Users\wohaoshuai\AppData\Local\Programs\Python\Python36\python.exe E:/PythonLearn/day15/multiprocessing_learn.py from parent [42, None, 'hello'] from parent2 [42, None, 'hello']
四、Pipes,和Queue差不多,也可以一对多。
1 #!/usr/bin/python 2 # -*- coding : utf-8 -*- 3 # 作者: Presley 4 # 时间: 2018-11-27 5 # 邮箱:1209989516@qq.com 6 # 这是我用来练习python多进程的测试脚本 7 8 from multiprocessing import Process,Pipe 9 10 def f(conn): 11 conn.send([42,None,"hello"]) 12 conn.close() 13 14 if __name__ == "__main__": 15 parent_conn,child_conn = Pipe() 16 p = Process(target=f,args=(child_conn,)) #子进程里send一个数据然后关闭 17 p2 = Process(target=f, args=(child_conn,)) # 子进程里send一个数据然后关闭 18 p.start() 19 p2.start() 20 print(parent_conn.recv()) #prints "[42,None,"hello"]" 21 print(parent_conn.recv()) 22 p.join()
执行结果:
C:\Users\wohaoshuai\AppData\Local\Programs\Python\Python36\python.exe E:/PythonLearn/day15/multiprocessing_learn.py [42, None, 'hello'] [42, None, 'hello'] Process finished with exit code 0
五、进程间实现数据共享 Manager
1 #!/usr/bin/python 2 # -*- coding : utf-8 -*- 3 # 作者: Presley 4 # 时间: 2018-11-27 5 # 邮箱:1209989516@qq.com 6 # 这是我用来练习python多进程的测试脚本 7 8 #进程间实现数据共享 9 from multiprocessing import Process,Manager #导入Manager 10 11 def f(d,l,n): 12 d[n] = n 13 d["2"] = 2 14 d[0.25] = None 15 l.append(n) 16 print(l) 17 18 if __name__ == "__main__": 19 with Manager() as manager: 20 d = manager.dict() 21 l = manager.list(range(5)) 22 p_list = [] 23 for i in range(10): 24 p = Process(target=f,args=(d,l,i)) 25 p.start() 26 p_list.append(p) 27 for res in p_list: 28 res.join() 29 print(d) 30 print(l)
执行结果:
C:\Users\wohaoshuai\AppData\Local\Programs\Python\Python36\python.exe E:/PythonLearn/day15/multiprocessing_learn.py [0, 1, 2, 3, 4, 3] [0, 1, 2, 3, 4, 3, 2] [0, 1, 2, 3, 4, 3, 2, 6] [0, 1, 2, 3, 4, 3, 2, 6, 1] [0, 1, 2, 3, 4, 3, 2, 6, 1, 7] [0, 1, 2, 3, 4, 3, 2, 6, 1, 7, 0] [0, 1, 2, 3, 4, 3, 2, 6, 1, 7, 0, 4] [0, 1, 2, 3, 4, 3, 2, 6, 1, 7, 0, 4, 9] [0, 1, 2, 3, 4, 3, 2, 6, 1, 7, 0, 4, 9, 5] [0, 1, 2, 3, 4, 3, 2, 6, 1, 7, 0, 4, 9, 5, 8] {3: 3, '2': 2, 0.25: None, 2: 2, 6: 6, 1: 1, 7: 7, 0: 0, 4: 4, 9: 9, 5: 5, 8: 8} [0, 1, 2, 3, 4, 3, 2, 6, 1, 7, 0, 4, 9, 5, 8] Process finished with exit code 0
六、进程同步
python3默认进程会自动加锁,但是python2不会
1 #!/usr/bin/python 2 # -*- coding : utf-8 -*- 3 # 作者: Presley 4 # 时间: 2018-11-27 5 # 邮箱:1209989516@qq.com 6 # 这是我用来练习python多进程的测试脚本 7 8 9 from multiprocessing import Process,Lock 10 11 def f(l,i): 12 l.acquire() 13 try: 14 print("hello world",i) 15 finally: 16 l.release() 17 18 19 if __name__ == "__main__": 20 lock = Lock() 21 for num in range(10): 22 Process(target=f,args=(lock,num)).start()
执行结果:
1 C:\Users\wohaoshuai\AppData\Local\Programs\Python\Python36\python.exe E:/PythonLearn/day15/multiprocessing_learn.py 2 hello world 3 3 hello world 6 4 hello world 2 5 hello world 7 6 hello world 0 7 hello world 5 8 hello world 1 9 hello world 4 10 hello world 8 11 hello world 9 12 13 Process finished with exit code 0
七、进程池
1、进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可用进程,那么程序就会等待,直到进程池中有可用进程为止。
2、进程池中有两个方法:
a、apply 同步
b、apply_async 异步
#!/usr/bin/python # -*- coding : utf-8 -*- # 作者: Presley # 时间: 2018-11-27 # 邮箱:1209989516@qq.com # 这是我用来练习python多进程的测试脚本 from multiprocessing import Process,Pool,freeze_support #在windows上需要导入freeze_support这个包使用,linux上不需要 import time def Foo(i): time.sleep(2) return i + 100 def Bar(arg): print("--> exec done",arg) if __name__ == '__main__': freeze_support() pool = Pool(5) #允许最大五个进程同时运行 for i in range(10): pool.apply_async(func=Foo,args=(i,),callback=Bar) #callback是回调函数,就是函数Foo执行完了再执行Bar,Foo的执行结果会自动传给Bar,就相当于打印出Foo的执行结果 #pool.apply(func=Foo,args=(i,)) #这个是同步,是串行执行,同步的时候不能使用callback方法 print("end") pool.close() pool.join() #进程池中执行完毕后再关闭,如果注释,那么程序直接关闭,按理来说应该程序执行完后再关闭线程池,但是python里面的写法就是这样的
执行结果:因为允许最大五个进程同时运行因此会每次先打印五个
C:\Users\wohaoshuai\AppData\Local\Programs\Python\Python36\python.exe E:/PythonLearn/day15/multiprocessing_learn.py end --> exec done 100 --> exec done 101 --> exec done 102 --> exec done 103 --> exec done 104 --> exec done 105 --> exec done 106 --> exec done 107 --> exec done 108 --> exec done 109 Process finished with exit code 0