Process
1.进程之间的数据隔离问题
2.守护进程
几个进程的模型 ---- 进程同步的工具
有先后顺序,就是同步
进程之间就是异步
希望原本异步的多进程操作,维持一个顺序---同步工具
1.锁 Lock
2.信号量 Semaphore
3.事件 Event
from mulitprocessing import Process
n = 100
def func():
global n
n = n-1
return 6666
if __name__ == "__main__":
nl = []
for i in range(100):
p = Process(target=func)
p.start()
nl.append(p)
for p in nl:
p.join()
print(n)
通过上面的代码我们知道进程与进程之间的数据是隔离的 , 内存空间是不能共享的 , 所以要想进行通信 , 必须借助其他手段,且这两个进程都是自愿的.
子进程的执行结果父进程获取不到 , 如果父进程依赖子进程的执行结果呢?父进程如何获取子进程的执行结果?
父子进程之间通过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("主进程")
例二:
def func1():
print("begin")
time.sleep(3)
print("wahaha")
def func2():
while True:
print("in func2")
time.sleep(0.5)
if __name__ =="__main__":
Process(target=func1).start()
p = Process(target=func2)
p.daemon = True
p.start()
time.sleep(1)
print("主进程")
设置成守护进程之后会有什么效果?
守护进程会在主进程的代码执行完毕之后直接结束,无论守护进程是否执行完毕
应用:
报活 : 主进程还活着
假如有100台机器,每台机器上有100个进程,总共10000个进程,守护进程如何向检测机制报活??为什么要用守护进程来报活呢?为什么不用主进程来工作呢?
因为守护进程报活几乎不占用CPU,也不需要操作系统去调度;且主进程有自己的任务,不能严格的按时就会发送一条报活信息
5.所有的进程的基本使用:
进程:同一时刻可以做多件事情互相之间不影响
socket tcp server 采用多进程的知识点来解决原生socket同一时刻只能和一个client通信的弊端
以下是代码的实现:
服务器:
import scoket
from multiprocessing import Process
def talk(conn):
try:
while 1:
conn.send(b"hello")
print(conn.recv(1024)
finally:
conn.close()
if __name__ == "__main__":
sk = socket.socket()
sk.bind(("127.0.0.1",9090))
sk.listen()
try:
while 1:
conn,addr = sk.accept()
Process(target=talk,args=(conn,)).start()
finally:
sk.close()
客户端:
import socket,os
sk = socket.socket()
sk.conn(("127.0.0.1",9090))
while 1:
print(sk.recv(1024)
sk.send(b"world")
sk.close()
6.锁
from multiprocessing import Lock,Process
lock = Lock() #创造了一把锁
lock.acquire() #获取了这把锁的钥匙
lock.release() #归还这把锁的钥匙
加锁就是谁先拿到钥匙谁先进.
我们通过一个例子来了解一下:
抢票的例子,每个人都能查看余票,买票
import json,time
from multiprocessing import Lock,Process
def search(i):
with open("db")as f:count_dic = json.load(f)
time.sleep(0.2)
print("person %s 余票:%s张"%(i,count_dic["count"])
def buy(i):
with open("db")as f:count_dic = json.load(f)
time.sleep(0.2)
if count_dic[''count''] > 0:
count_dic[''count''] -= 1
print("person %s购票成功"%i)
time.sleep(0.2)
with open("db","w")as f: json.dump(count_dic,f)
def task(i,lock):
search(i)
lock.acquire()
buy(i)
lock.release()
if __name__ == "__main__":
lock = Lock()
for i in range(10):
p = Process(target=task,args=(i,lock))
p.start()
当多个进程共享一段数据的时候,数据会出现不安全的现象,需要加锁来维护数据的安全性
lock =Lock()
lock.acquire() #拿钥匙
print(1111)
lock.release() #还钥匙
lock.acquire() #阻塞,如果上面没有还钥匙就会阻塞
print(2222)
7.信号量
from multiprocessing import Process,Semaphore
sef =Semaphore(3) #信号量
sem.acquire()
print(1)
sem.acquire()
print(2)
sem.acquire()
print(3)
sem.acquire() #阻塞,因为只有三把钥匙,且上面没有还钥匙的过程
print(4)
import time,random
from multiprocessing import Process,Semaphore
def ktv(num,sem):
sem.acquire()
print("person %s 进了KTV"%num)
time.sleep(random.randint(1,4))
print("person %s 出来了"%num)
sem.release()
if __name__ == "__main__":
sem = Semaphore(3)
for i in range(10):
p = Process(target=ktv,args=(i,sem))
p.start()
信号量的本质 : 多把钥匙对应一把锁, lock + count计数
8.事件
并发的时候,很多模型,事件
from multiprocessing import Event , Process
wait() 方法 : 等待
阻塞 :如果这个标志是False ,那么就是阻塞
非阻塞:如果这个标志是True,那么就是非阻塞
查看标志的方法: is_set()
修改标志 : set()将标志设置为True
clear()将标志设置为False
e = Event()
print(e.is_set()) #在事件的创建之初默认是False
e.set() #将标志设置为True
print(e.is_set())
e.wait() #相当于什么都没有做pass,因为当前标志是True,非阻塞状态
e.clear() #将标志设置为False
e.wait() #永远阻塞
e.wait(timeout = 10)#如果信号在阻塞10s之内变为True,那么不继续阻塞直接pass,如果阻塞10s之后代码继续执行,但是状态没有变.
print(e.is_set())#无论前面的wait的timeout是否通过,我的状态都不会因此改变.
红绿灯模型
控制交通灯的过程
import time,random
from multiprocessing import Process,Event
def traffic_light(e):
print(" 33[1;31m 红灯亮 33[0m")
while 1:
time.sleep(2)
if e.is_set():
print(" 33[1;31m 红灯亮 33[0m")
e.clear()
else:
print(" 33[1;32m 绿灯亮 33[0m")
e.set()
车 等或者通过
def car(id,e):
while 1:
if not e.is_set():
print("car %s 等待"%id)
e.wait()
print("car %s 通过"%id)
def police_car(id,e):
if not e.is_set():
e.wait(timeout=0.5)
print("police_car %s通过"%id)
主进程 启动交通控制灯 启动车的进程
if __name__ == "__main__":
e = Event()
Process(target=traffic_light,args = (e,))
nl = [police_car,car]
for i in range(20):
p =Process(target=random.choice(nl),args=(i,e))
p.start()
time.sleep(random.randrange(0,3,2))
总结:
进程之间的数据是隔离的
进程与进程之间是不能自由的交换内存数据的
全局的变量在子进程中修改 其他进程是感知不到的
守护进程
特点 : 生命周期只和主进程的代码有关系,和其他子进程没关系
用处 : 报活
多进程启动tcp协议的socket来完成并发
进程的同步控制 -- 进程之间有一些简单的信号传递,用户是感知不到的,且用户不能传递自己想传递的内容
锁 *****
信号量 锁 + 计数器实现
事件 wait
事件 : 通过一个标记来控制多个进程进行同步控制
在某个地方wait是否有阻塞的行为是根据事件对象内部的一个标记来决定的
在事件对象中提供的方法可以修改这个标记的状态