并发编程:创建进程 join方法 进程间的数据隔离问题 进程对象以及其他方法 守护进程 互斥锁
创建进程的两种方式
创建进程的过程:
创建进程就是在内存中重新开辟一块内存空间将允许产生的代码丢进去。
一个进程对应在内存就是一块独立的内存空间进程与进程之间数据是隔离的,无法直接交互但是可以通过某些技术实现间接交互。
使用process模块时需要注意:
在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),
在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。
因此如果将process()直接写在文件中就会无限递归创建子进程报错。
所以必须把创建子进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候,就不会递归运行了。
第一种方式:
1 from multiprocessing import Process 2 import time 3 4 5 def test(name): 6 print('%s is running'%name) 7 time.sleep(3) 8 print('%s is over'%name) 9 10 """ 11 windows创建进程会将代码以模块的方式 从上往下执行一遍 12 linux会直接将代码完完整整的拷贝一份 13 14 15 windows创建进程一定要在if __name__ == '__main__':代码块内创建 否则报错 16 """ 17 if __name__ == '__main__': 18 p = Process(target=test,args=('egon',)) # 创建一个进程对象 19 p.start() # 告诉操作系统帮你创建一个进程 20 print('主')
第二种方式:
1 # 创建进程的第二种方式 2 from multiprocessing import Process 3 import time 4 5 6 class MyProcess(Process): 7 def __init__(self,name): 8 super().__init__() 9 self.name = name 10 11 def run(self): 12 print('%s is running' % self.name) 13 time.sleep(3) 14 print('%s is over' % self.name) 15 16 17 if __name__ == '__main__': 18 p = MyProcess('egon') 19 p.start() 20 print('主')
join方法:
p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。
timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
注意:多个进程同时运行(注意,子进程的执行顺序不是根据启动顺序决定的)
1 import time 2 from multiprocessing import Process 3 4 def f(name): 5 print('hello', name) 6 time.sleep(1) 7 print('我是子进程') 8 9 10 if __name__ == '__main__': 11 p = Process(target=f, args=('bob',)) 12 p.start() 13 #p.join() 14 print('我是父进程')
1 from multiprocessing import Process 2 import time 3 4 def test(name,i): 5 print('%s is running'%name) 6 time.sleep(i) 7 print('%s is over'%name) 8 if __name__ == '__main__': 9 p_list = [] 10 # for i in range(3): 11 # p = Process(target=test,args=('进程%s'%i,i)) 12 # p.start() 13 # p_list.append(p) 14 # for p in p_list: 15 # p.join() 16 p = Process(target=test,args=('egon',1)) 17 p1 = Process(target=test,args=('kevin',2)) 18 p2 = Process(target=test,args=('jason',3)) 19 start_time = time.time() 20 p.start() # 仅仅是告诉操作系统帮你创建一个进程 至于这个进程什么时候创 操作系统随机决定 21 p1.start() 22 p2.start() 23 p2.join() 24 p.join() 25 p1.join() 26 27 # 主进程代码等待子进程运行结束 才继续运行 28 # p.join() # 主进程代码等待子进程运行结束 29 print('主') 30 print(time.time() - start_time)
进程间的数据的隔离问题:
对进程中数据修改不会影响其他进程中的数据!
1 from multiprocessing import Process 2 3 def work(): 4 global n 5 n=0 6 print('子进程内: ',n) 7 8 9 if __name__ == '__main__': 10 n = 100 11 p=Process(target=work) 12 p.start() 13 print('主进程内: ',n)
进程中的其他常用方法:
p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True
1 from multiprocessing import Process,current_process 2 import os 3 import time 4 5 6 def test(name): 7 # print('%s is running'%name,current_process().pid) 8 print('%s is running'%name,'子进程%s'%os.getpid(),'父进程%s'%os.getppid()) 9 time.sleep(3) 10 print('%s is over'%name) 11 12 13 if __name__ == '__main__': 14 p = Process(target=test,args=('egon',)) 15 p.start() 16 p.terminate() # 杀死当前进程 其实是告诉操作系统帮你杀死一个进程 17 time.sleep(0.1) 18 print(p.is_alive()) # 判断进程是否存活 19 # print('主',current_process().pid) 20 print('主', os.getpid(), '主主进程:%s'%os.getppid())
属性:
1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的子进程,必须在p.start()之前设置
2 p.name:进程的名称
3 p.pid:进程的pid
4 查看进程的pid os.getpid()
1 from multiprocessing import Process 2 import time 3 4 5 def test(name): 6 print('%s总管正常活着'%name) 7 time.sleep(3) 8 print('%s总管正常死亡'%name) 9 10 11 if __name__ == '__main__': 12 p = Process(target=test,args=('egon',)) 13 p.daemon = True # 将该进程设置为守护进程 这一句话必须放在start语句之前 否则报错 14 p.start() 15 time.sleep(0.1) 16 print('皇帝jason寿正终寝')
互斥锁:
1 from multiprocessing import Process,Lock 2 import time 3 import json 4 5 # 查票 6 def search(i): 7 with open('data','r',encoding='utf-8') as f: 8 data = f.read() 9 t_d = json.loads(data) 10 print('用户%s查询余票为:%s'%(i,t_d.get('ticket'))) 11 12 # 买票 13 def buy(i): 14 with open('data','r',encoding='utf-8') as f: 15 data = f.read() 16 t_d = json.loads(data) 17 time.sleep(1) 18 if t_d.get('ticket') > 0: 19 # 票数减一 20 t_d['ticket'] -= 1 21 # 更新票数 22 with open('data','w',encoding='utf-8') as f: 23 json.dump(t_d,f) 24 print('用户%s抢票成功'%i) 25 else: 26 print('没票了') 27 28 29 def run(i,mutex): 30 search(i) 31 mutex.acquire() # 抢锁 只要有人抢到了锁 其他人必须等待该人释放锁 32 buy(i) 33 mutex.release() # 释放锁 34 35 36 if __name__ == '__main__': 37 mutex = Lock() # 生成了一把锁 38 for i in range(10): 39 p = Process(target=run,args=(i,mutex)) 40 p.start()