进程、线程、协程篇(下)
多进程multiprocessingmultiprocessing是一个包,它支持使用与线程模块类似的API生成进程。多处理包提供了本地和远程并发性,通过使用子进程而不是线程有效地绕过了全局解释器锁。因此,多处理模块允许程序员充分利用给定机器上的多个处理器。它可以在Unix和Windows上运行 #Author:AZ import multiprocessing import time,threading def thread_run(): print(threading.get_ident()) def run(name): time.sleep(2) print("hello",name) t = threading.Thread(target=thread_run,) t.start() if __name__ == ‘__main__‘: for i in range(10): p = multiprocessing.Process(target=run,args=("bob %s" %i,)) p.start() ?为了显示所涉及的各个进程id,下面是一个扩展示例,getppid()获取父进程id,getpid()获取进程id,所有进程都有一个父进程 #Author:AZ from multiprocessing import Process import os def info(title): print(title) print(‘module name:‘,__name__) print(‘parent process:‘,os.getppid())#获取父进程ID(pycharm进程) 所有进程都有一个父进程 print(‘process id:‘,os.getpid())#获取进程id print("nn") def f(name): info(‘ 33[31;1mcalled from child process function f 33[0m‘) print(‘hello‘,name) if __name__ == ‘__main__‘: info(‘ 33[32;1mmain process line 33[0m‘) p = Process(target=f,args=(‘bob‘,)) p.start() # p.join() ?进程间通讯 不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法: Queues 使用方法跟threading里的queue差不多 #Author:AZ from multiprocessing import Process,Queue import threading def f(qq): qq.put([43,None,‘hello‘])#子进程q if __name__ == ‘__main__‘: q = Queue()#父进程q, p = Process(target=f,args=(q,)) p.start() print(q.get()) p.join() ?注:这里的父进程和子进程是两个进程,子进程克隆父进程, 子进程通过pickl序列化传值,通过反序列化把值传给父进程, 另外,此处进程和线程不同,不是对同一进程的修改,而是两个进程间的值的传递。 Pipes 函数的作用是:返回一对由管道连接的连接对象,默认情况下管道是双工(双向)的。例如: #Author:AZ from multiprocessing import Process,Pipe def f(conn): conn.send([42,‘hello from child‘]) conn.send([42,‘hello from child2‘]) print("from parent:",conn.recv()) conn.close() if __name__ == ‘__main__‘: parent_conn,child_conn = Pipe()#管道两端 p = Process(target=f,args=(child_conn,)) p.start() print(parent_conn.recv()) # prints "[42,‘hello‘]" print(parent_conn.recv()) # prints "[42,‘hello‘]" parent_conn.send("张洋可好") # prints "[42,‘hello‘]" p.join() ?Pipe()返回的两个连接对象表示管道的两端。每个连接对象都有send()和recv()方法(以及其他方法)。 注意,如果两个进程(或线程)试图同时从管道的同一端读取或写入数据,管道中的数据可能会损坏。 当然,同时使用管道的不同端不会有进程损坏的风险。 Managers manager()返回的manager对象控制一个服务器进程,该进程持有Python对象,并允许其他进程使用代理操作它们。 manager()返回的管理器将支持类型列表、dict、名称空间、锁、RLock、信号量、有界信号量、条件、事件、屏障、队列、值和数组,可以实现这些数据的共享。例如 #Author:AZ from multiprocessing import Process,Manager import os def f(d,l): d[os.getpid()] = os.getpid() l.append(os.getpid()) print(l) print("=================================") if __name__ == ‘__main__‘: with Manager() as manager: d = manager.dict() #生成一个字典,可在多个进程之间共享 l = manager.list(range(5)) #生成一个列表,可在多个进程之间共享 p_list =[] for i in range(10): p = Process(target=f,args=(d,l)) p.start() p_list.append(p) for res in p_list:#等待结果 res.join() print(d) print(l) ?进程同步 使用进程锁(Lock)实现进程同步,防止不同进程的结果输出混淆。 from multiprocessing import Process,Lock def f(l,i): l.acquire() try: print(‘hello world‘,i) finally: l.release() if __name__ == ‘__main__‘: lock = Lock() for num in range(10): Process(target=f,args=(lock,num)).start() ?进程池 进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。 进程池中有两个方法:
#Author:AZ from multiprocessing import Process,Pool,freeze_support import time import os def Foo(i): time.sleep(2) print("in process",os.getpid()) return i + 100 def Bar(arg): print(‘-->exec done:‘,arg,os.getpid()) if __name__ ==‘__main__‘: pool =Pool(processes=5) #允许同时放入5 个进程 print("主进程",os.getpid()) for i in range(10): pool.apply_async(func=Foo,args=(i,),callback=Bar) #callback=回调, # pool.apply(func=Foo,)) #串行=同步传输 # pool.apply_async(func=Foo,)) #并行=异步传输 print(‘end‘) pool.close() pool.join()#进程池中进程执行完毕后再关闭, # 如果注释 pool.join(),或把它放在close()函数之前,那么程序直接关闭。 #导致一些程序还未执行完 ?注:callback,回调功能,即是子进程执行完后,主进程回调程序,原因是主进程持续连接着服务器,而子进程在不断切换 此功能可以用于在执行子进程备份数据后,写log日志模块等...... 另外,pool.join()必须在pool.close()执行后执行。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |