进程数据隔离.守护进程,进程同步工具
一.进程之间的数据隔离:
from multiprocessing import Process n=100 #主程序中变量n= def func(): global n #子进程中引用父进程中变量n, n=n-1 return 111 if __name__=="__main__": # "子进程必须写在它下面" n_l=[] # 建立一个新列表 for i in range(100): #计数 p=Process(target=func) #建立一个子进程,子进程对象是func p.start() #向操做系统申请开启一个子进程 自动执行run 方法 n_l.append(p) # 将每个子进程添加到列表中 print(n_l) #列表里是相似于<Process(Process-1, stopped)>的元素 for p in n_l: #循环遍历 每个元素 p.join() #全部子进程都结束在执行下面的程序 print(n) #100 #结果=100 显然子进程并无引用到父进程的变量.
进程之间的数据隔离:
总结:
1.进程与进程之间数据是隔离的,
2.内存空间是不能共享的
3.因此想要进行通讯,必须借助其余手段,且这两个进程都是自愿的.
4.子进程的执行结果父进程获取不到
5.父进程如何获取子进程的执行结果:经过socket通讯.
二.守护进程:
import time
from multiprocessing import Process
例一.
def func():
print("begin")
time.sleep(3)
print("wahaha")
if __name__=="__main__":
p=Process(target=func)
p.daemon=True
注意:
# 属性:守护进程的属性,默认是False,若是设置成True,就表示设置这个子进程为一个守护进程
# 守护进程的位置:设置守护进程的操做应该在开启子进程以前
p.start()
time.sleep(1)
print("主进程") #结果 只打印begin 主进程,
#例二: def func1(): print("begin") #2打印begin time.sleep(3) #3 休三秒 print("wahaha") #12.打印 wahaha def func2(): while True: print("in func2") #7.打印 in func2 9.打印infunc2 time.sleep(0.5) #8.睡0.5秒 if __name__=="__main__": Process(target=func1).start() #1 建立一个子进程,子进程对象为func1,并向操做系统申请开启 p=Process(target=func2) #4 再建立一个子进程,子进程对象为func2, p.daemon=True #5.设置守护进程操做 p.start() # 6.申请开启子进程func2 time.sleep(1) #10睡 1秒 print("主进程") #11.打印主进程
总结:
守护进程会在主进程的代码执行完毕以后直接结束,不管守护进程是否执行完毕
应用:
报活 主进程还活着
为何要用守护进程来报活,不用主进程来工做?
守护进程报活几乎不占用CPU,也不须要操做系统去调度
主进程不能严格的每60秒就发送一条信息.
三.进程同步的工具
相关知识:
进程 : 同一时刻能够作多件事情 互相之间不影响
进程之间是异步;
进程同步的工具:锁( Lock ),信号量( Semaphore ) ,事件( Event )
同步:有前后顺序
(一). 锁Lock from multiprocessing import Lock lock=Lock() #建立一把锁 #两个方法 lock.acquire() #获取这把锁的钥匙 lock.release() #归还这把锁的钥匙 #抢票的例子(每一个人都能查看余票,买票 import json #导入json模块 import time #导入时间模块 from multiprocessing import Process #导入Process模块 from multiprocessing import Lock #导入Lock模块 def search(i):#定义一个查票函数 with open("db","r")as f: # 2 打开文件,读取文件数据 count_dic=json.load(f) # 3 将读取数据反序列化获得数据自己 time.sleep(0.2) # 4网络延迟 从数据库中读取内容须要消耗必定的时间. print("person%s 余票:%s张"%(i,count_dic["count"])) # 5.显示用户信息和查询数据 def buy(i): #定义一个购票函数 with open("db","r",encoding="utf-8")as f: # 8.打开文件,读取数据 count_dic=json.load(f) # 9.反序列化获得原数据 if count_dic["count"]>0: # 10.判断剩余票数是否>0 count_dic["count"]=count_dic["count"]-1 # 11.大于零则将原票数减1 print("person%s购票成功"% i) # 12显示用户购票成功 time.sleep(0.2) # 13网络延迟 (给数据库传递新票务信息须要时间) with open("db","w",encoding="utf-8")as f: # 14打开文件 json.dump(count_dic,f) # 15 将更改后的数据写进数据库 def task(i,lock): #定义一个任务函数 search(i) # 1 执行函数search ,将序号i传给函数search lock.acquire() # 6.用lock的acquire方法获取这把锁钥匙 (buy函数被建立的锁锁住) buy(i) # 7.执行函数buy() 并将参数i传给函数 lock.release() # 16 用户归还钥匙 if __name__=="__main__": #必须在这一步下面建立子进程 lock=Lock() #建立一个锁lock for i in range(10): #计数10如下 p=Process(target=task,args=(i,lock)) #建立一个子进程,子进程对象是task,有两个参数(一个是序号i,一个是加锁) 须要建立十个子进程 p.start() #申请开启一个子进程 应用:
当多个进程共享一段数据的时候,数据会出现不安全的现象,须要加锁来维护数据的安全性 注意: from multiprocessing import Lock lock=Lock() lock.acquire() print(111) lock.release() lock.acquire() # 阻塞状态 (只有一把钥匙已经被获取,且还没有归还) print(222) #不加只打印111 #解决办法: 只须要在第二次获取钥匙前将钥匙归还即加上 lock.release() 加上lock.release()就能够打印111,222
(二).信号量(Semaphore)
信号量的本质: 多把钥匙对应一把锁
lock+count计数
现象:
from multiprocessing import Process from multiprocessing import Semaphore sem=Semaphore(3) sem.acquire() print(1) sem.acquire() print(2) sem.acquire() print(3) #sem.release() sem.acquire() #阻塞状态 若是加sem.release() print(4) #不打印
案例:商场唱吧(KTV)
场景:四个小房子,十我的排队等待进入房间
import time #导入时间模块 import random #导入random模块 from multiprocessing import Process #导入Process模块 from multiprocessing import Semaphore #导入Semaphore信号量 模块 def ktv(num,sem):#定义一个函数ktv sem.acquire() # 1 获取一把钥匙 6 下一个用户(进程)获取钥匙 print("person%s进入ktv"% num) # 2 显示用户信息及正在使用状态 time.sleep(random.randint(1,4)) # 3 使用时间段 print("person%s离开ktv"% num) # 4 显示用户离开 sem.release() # 5 归还钥匙 if __name__=="__main__": #必须在这一条件下面建立新进程 sem=Semaphore(4) #可容许四人同时使用 for i in range(10): #计数 一共须要建立十个子进程 p=Process(target=ktv,args=(i,sem)) # 建立一个子进程p 子进程对象为ktv.须要两个参数(序号,sem) p.start() # 申请开启一个子进程 归还钥匙后,
(三).事件(Event)
方法:
等待: wait() 若是这个标志是False 那么就阻塞
若是这个标志是True 那么就非阻塞
查看标志: is_set()
修改标志:set()将标志设置为True
clear()将标志设置为False
现象: from multiprocessing import Event e = Event() print(e.is_set()) #False 在事件建立之初默认是False e.set() #将标志设置为True print(e.is_set()) #True e.wait() #至关于什么也没作 e.clear() #将标志设置为False e.wait(timeout=10) #阻塞10秒若是信号在阻塞10s以内变为True,那么不继续阻塞直接pass, # # 若是就阻塞10s以后状态仍是没变,那么继续, # e.wait()能够加参数 # 不管前面的wait的timeout是否经过,个人状态都不会所以改变 print(e.is_set()) #False
红绿灯模型: 控制交通灯的进程; import time import random from multiprocessing import Event from multiprocessing import Process def trafic_light(e): print("\033[1;31m红灯亮\033[0m") # 1 打印红灯亮 while True: #2无限循环 time.sleep(2) #3睡两秒 # print(1,e.is_set()) #f if e.is_set(): # 4.条件e.is_set()=False:阻塞 print("\033[1;31m红灯亮\033[0m") #5.打印红灯亮 e.clear() #6.修改is_set()的状态为False # time.sleep(3) # print(2,e.is_set()) #f else: #7.e.si_set==True若是目前状态是True非阻塞 print("\033[1;32m绿灯亮\033[0m") #8.打印绿灯亮 # print(4, e.is_set()) #f e.set() #9.设置is_set的状态为True 非阻塞(通行) # print(5,e.is_set()) #T def car(i,e):#车函数 (两种状况:等待,通行) # time.sleep(3) # print(3,e.is_set()) #True if not e.is_set():# 10.若是e.is_set()的状态是True 则not e.is_set()为False,如今状态是阻塞, print("car%sd等待"% i) #11. #先提示用户进入等待状态 e.wait() #12. #直接pass print("car%s通行"% i) #13.和条件判断并行即条件不知足执行这一步 if __name__=="__main__": e=Event() #建立一个事件 p=Process(target=trafic_light,args=(e,)) #建立一个进程对象为trafic_light ,参数为e p.start() #申请开启进程 for i in range(10): p=Process(target=car,args=(i,e)) #建立十个car进程,参数为i,e p.start() #申请开启进程 time.sleep(random.randrange(0, 3, 2)) #要么睡两秒,要么不睡.
多进程解决tcp协议一个服务器与多个客户端通讯矛盾python
服务器端代码:数据库
import socket from multiprocessing import Process #导入类Process def talk(conn): # 0 定义一个函数talk 6.执行talk进程 try: while True: conn.send(b'alex') #7.发送信息 print(conn.recv(1024)) #8.接收信息 finally: conn.close() if __name__=="__main__": sk=socket.socket() # 1 建立一个socket对象 sk.bind(("127.0.0.1",9901)) # 2 绑定一个IP地址接口 sk.listen() #3 监听 try: while True: conn,addr=sk.accept() #4 无限循环可支持多个客户端链接 Process(target=talk,args=(conn,)).start() #5 链接之后须要开启一个正常收发信息进程.进程对象就是talk #并向操做系统提出执行talk进程的申请. finally: sk.close()
客户端代码:json
import socket import os sk=socket.socket() sk.connect(("127.0.0.1",9901)) while True: print(sk.recv(1024)) sk.send(str(os.getpid()).encode('utf-8')) sk.close()