python之路(14)进程
目录
进程创建
创建进程实现在python下的并发,同时调用多个cpu来操作线程
方法一:
from multiprocessing import Process import time def f(name): time.sleep(1) print('hello', name,time.ctime()) if __name__ == '__main__': p_list=[] for i in range(3): #开启三个进程,此时是使用3个cpu,每个cpu分别执行一个 p = Process(target=f, args=('alvin',)) p_list.append(p) p.start() for i in p_list: i.join() print('end')
方法二:通过继承
from multiprocessing import Process import time class MyProcess(Process): # def __init__(self): # super(MyProcess, self).__init__() # #self.name = name def run(self): time.sleep(1) print ('hello', self.name,time.ctime()) #self.name是进程名 if __name__ == '__main__': p_list=[] for i in range(3): p = MyProcess() # p.daemon=True #设置为守护进程 p.start() p_list.append(p) for p in p_list: p.join() #如果子进程没有执行完,主进程就卡在这里,不往下运行 print('end') ######################################### hello MyProcess-1 Sat May 4 15:42:00 2019 hello MyProcess-2 Sat May 4 15:42:00 2019 hello MyProcess-3 Sat May 4 15:42:00 2019 end
os.getppid() 显示父进程的id
os.getpid() 显示当前进程的id
p.is_alive() 实例方法,判断进程是否还活着
p.terminate() 直接停止进程运行
进程间通信
进程间通信与线程间通信不同,线程之间共享一块内存,简单的线程间通信只要设置全局变量或者同步对象event(具体看进程篇)就能做到。而进程在不同的两块内存之中。
方案一:使用进程队列来实现进程间通信
import time import multiprocessing def foo(q): time.sleep(1) print("son process",id(q)) q.put(123) #在子进程中放入值 q.put("chen") if __name__ == '__main__': q=multiprocessing.Queue() #创建进程队列 p=multiprocessing.Process(target=foo,args=(q,)) #在进程之间传递进程队列,作为全局变量 p.start() print("main process",id(q)) print(q.get()) #在主进程中拿出数据 print(q.get())
方案二:使用双向管道来实现经常队列
from multiprocessing import Process, Pipe def f(conn): conn.send([12, {"name":"chen"}, 'hello']) #子进程给主进程发送数据 response=conn.recv() #子进程接收主进程发送的数据 print("response",response) 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, None, 'hello']" parent_conn.send("儿子你好!") #主进程给子进程发送数据 p.join()
方案二:使用Manager实现进程间通信
Pipe和Queue只是实现了进程间数据的交互,并没有实现进程间数据共享,即一个进程修改另一个进程的数据
Manager支持的类型有list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value和Array。
from multiprocessing import Process, Manager def f(d, l,n): d[n] = '1' #{0:"1"} d['2'] = 2 #{0:"1","2":2} l.append(n) #[0,1,2,3,4, 0,1,2,3,4,5,6,7,8,9] if __name__ == '__main__': with Manager() as manager: #with语法自动close() d = manager.dict()#通过manager得到一个字典对象 l = manager.list(range(5))#通过manager得到一个列表对象 p_list = [] for i in range(10): p = Process(target=f, args=(d,l,i)) #将通过manager创建的对象最为参数传入子进程中 p.start() p_list.append(p) for res in p_list: res.join() print(d) print(l)
注:进程间的通信是很耗费资源的,因为存在两块不同的内存之中,所以本质上是一个进程将数据拷贝到另一个进程,存在内存的消耗。
进程同步(同步锁)和进程池
在进程与进程之间的数据不共用,但是进程与进程间也有同时使用的系统资源,比如终端和屏幕,在多个进程向显示器输出内容的时候,可能会导致数据混乱的显现,比如:
因此使用进程同步锁来规定同一时刻,只能有一个进程来使用共用资源。
from multiprocessing import Process, Lock import time def f(lock, i): lock.acquire() #请求同步锁 time.sleep(1) print('hello world ',i) lock.release() #释放同步锁 if __name__ == '__main__': lock = Lock() #创建同步锁 for num in range(10): Process(target=f, args=(lock, num)).start()
进程池
在内存中同时会有很多的进程需要执行,那改怎么去执行这些进程成了问题,如果去同时运行这些进程那就太耗费资源,但是一个一个执行就费时,因此引入进程池,使用一个折中 的办法,在进程池中指定最大执行进程数量,进程的完执行速度有快有慢,当进程池中的某个进程执行完,等待的进程就可以进入进程池执行,直到完成所有进程的执行。
#每一秒执行5个进程 from multiprocessing import Pool import time def Foo(i): time.sleep(1) print(i) return "HELLO %s"%i def Bar(arg): print(arg) print("hello") if __name__ == '__main__': pool = Pool(5) #定义进程池的最大进程数。如果不指定数目,默认根据电脑的cpu数量 for i in range(100): #开一百个子进程 #开启进程池 pool.apply_async(func=Foo, args=(i,),callback=Bar) #callback指定回调函数(就是某个动作或者函数执行成功后再去执行的函数) pool.close() pool.join() # join与close调用顺序是固定的