python多进程
首先进程是资源调度的一个最小集合,通常起一个进程,然后通过操作系统完成资源的调度。具体的细节还需要进修。。。。。
总之,通过python也可以实现多进程的。
通常,我们启动一个进程的时候,都是通过父进程来启动这个对应的子进程,在python中,我们可以通过os模块,通过os.getpid()&os.getppid()来查看当前进程以及父进程的进程ID。或者我们可以通过multiprocessing模块中的创建一个进程的实例化对象后,通过调用pid这个方法来查看这个进程的进程ID。
当我们利用多进程的时候,就可以实现同一时间内做多件事情。在python中,如果我们启动多个子进程,主进程的执行和子进程的执行是没有影响的,但是,如果你想实现等待子进程执行完毕后才允许主进程执行完毕,可以利用join()方法,这里的join就相当于wait,就是,等待这个进程执行完毕,才进行下一步。 同样,当主进程执行完毕后,程序并不会退出,而是等待子进程也执行完毕才会退出,这时候,如果我们想实现主进程执行完毕后,某些子进程必须跟随者主进程的结束而结束,就可以设置某个子进程p,令其p.daemon = True,使这个进程变成守护进程,这样,当主进程执行完毕后,守护进程便会跟着退出(不管它执行完毕与否)。 更直白一点,就像古代皇帝死后,一些妃子需要陪葬,大臣不需要陪葬,这时候,这些妃子就相当于守护进程。。。
插入一段代码。。研究一下。
from multiprocessing import Process import time def func(): time.sleep(5) print('^^'*5) def run(): time.sleep(1) print('i am running') if __name__ == '__main__': p1 = Process(target=run) p1.daemon = True p1.start() p2 = Process(target=func) p2.start() print(p2.pid) for i in range(5): time.sleep(0.1) print('i am chief process')
除了这些之外,多进程还有某些特性。假设你要实现一个抢票功能,这时候,你想着so easy,每个人抢票的行为作为一个进程,不就可以实现同时抢票了吗?于是开始bangbangbang敲好了代码,测试的时候发现为什么只放出去一张票,好几个人抢到了,这是因为,起多个进程,他们有可能同时读入这个数据,导致疯狂被投诉。。。这时候,不要慌,进程里面还有进程锁这个东西,什么意思呢,就是好比你去拉屎,拉屎的时候肯定只能一人一个坑位,你进去了把门锁住,防止别人进来(除非你不是在拉屎,里面有俩人。。咳咳)。进程所就是,你要获取这个数据,你刚刚得到这个数据要进行处理,这个时候,你就把门反锁住,等你处理完了再把门打开,钥匙挂到门上,这样就避免了bug。 如果你说,一次只能进一个人这样太不友好了,我就是喜欢群P,怎么办?你可以在门上挂多点钥匙啊,这样不就可以好多人进去,限制了进去的人的数量。。。。这种可以有多个钥匙的锁称为“信号量”(semaphore)。
给你一个抢票的游戏:
from multiprocessing import Process from multiprocessing import Lock import time import random import json def search_ticket(): with open('ticket') as f: ticket = (json.load(f)['count']) print('there is %s tickets'%ticket) return ticket def get_ticket(i,lock): count_ticket = search_ticket() lock.acquire() if count_ticket: print('%s has gotten a ticket'%i) count_ticket -= 1 with open('ticket','w') as f: json.dump({'count':count_ticket},f) else: print('there is no ticket') lock.release() if __name__ == "__main__": lock = Lock() for i in range(10): time.sleep(random.randint(0,1)) p = Process(target=get_ticket,args=(i,lock)) p.start()
这里用json文件代表抢票的数据库,插入random和time模块模拟实际抢票过程中的网络时延。
接下来用信号量来模拟一下拉屎这个环节,每个人都有0-3秒的时间,毕竟超过三秒都是病。。。
from multiprocessing import Process from multiprocessing import Semaphore import time import random def toilet(i,sem): sem.acquire() print('%s 进去拉屎了'%i) time.sleep(random.randint(0,3)) sem.release() print('%s 已经拉完出来了,很饱'%i) if __name__ == '__main__': sem = Semaphore(4) for i in range(10): p = Process(target=toilet,args=(i,sem)) p.start()
除了锁这个概念外,进程还有一些小知识点需要掌握,队列和事件。队列很简单,无非就是先进先出,进去出去的原则,除此之外,还有qsize这个用法,但是再多进程中,这个方法有可能不准确,因为如果你读取一个数据的size的同时,又put进去了一个数据,通过队列可以实现子进程和主进程以及子进程和子进程之间的通信。
事件的话,就是可以模拟红绿灯,Event只需要记住这几个就行,clear/set/wait/is_set,当is_set为True的时候,程序是不阻塞的,默认情况下,wait是阻塞的,这样说也不大明白,还是插入一段红绿灯的例子:
from multiprocessing import Event from multiprocessing import Process import time def traffic_light(e): while True: if e.is_set(): print('绿灯,可以通过') time.sleep(2) e.clear() else: print('红灯,不能通过') time.sleep(3) e.set() def car(i,e): e.wait() print('%s 车可以通过'%i) if __name__ == '__main__': e = Event() p1 = Process(target=traffic_light,args=(e,)) p1.start() for i in range(20): if i % 3 == 0: time.sleep(3) else: p = Process(target=car,args=(i,e)) p.start()
此例中,假设车流量比较小,每三秒过来两辆车,红绿灯启用一个进程,每辆车也视为一个进程,通过事件e的is_set的布尔值的变化实现了进程间的通信。