多进程小结

守护进程 了解

什么是守护进程

在python中 守护进程也是一个进程,

默认情况下 主进程即使代码执行完毕了 也会等待子进程结束才会结束自己

当一个进程b设置为另一进程a的守护进程时 a是被守护 b是守护进程

特点是: 当被守护a 结束时,即使b的任务没有完成也会随之结束

 

比喻:

康熙 是一个进程 妃子是康熙的守护进程

康熙驾崩了 如果妃子还活着 那就陪葬去 当然如果妃子的任务提前结束了那就立即挂了

案例:

from multiprocessing import Process
import time


def task():
   print("zi run")
   time.sleep(3)
   print("zi over")

if __name__ == '__main__':
   p = Process(target=task)
   p.daemon = True  # 将这个进程设置为了守护进程 必须在开启进程前设置
   p.start()
   print("主over")

进程安全问题

当并发的多个任务,要同时操作同一个资源,就会造成数据错乱的问题

解决的方法:是,将并发操作公共资源的代码 由并发变为串行 解决安全问题,但是牺牲效率

串行方式1:

直接使用join函数

缺点: 将任务中所有代码全都串行 此时还是不如不要开进程

多个进程之间原本公平竞争 join是强行规定了执行顺序

串行方式2:互斥锁 重点

其原理就是将要操作公共资源的代码锁起来 以保证同一时间只能有一个进程在执行这部分代码

互斥锁是什么

互相排斥的锁

优点: 可以仅将部分代码串行

注意: 必须保证锁只有一把

和join区别

join是将所有子进程转为串行 锁 将部分需要的转为串行

join固定死了任务的执行顺序 锁 多进程之间还是公平竞争

 

使用方式:

from multiprocessing import Process,Lock
import time,random

def task1(mutex):
   # 假设这不是访问公共资源 那么还可也并发执行
   for i in range(10000):
       print(1)

   mutex.acquire() # 这是加锁
   time.sleep(random.random())
   print("-------name is nick")
   time.sleep(random.random())
   print("-------gender is girl")
   time.sleep(random.random())
   print("-------age is 18")
   mutex.release() # 解锁
   
   
def task2(mutex):
   for i in range(10000):
       print(2)

   mutex.acquire()
   time.sleep(random.random())
   print("++++++++name is bgon")
   time.sleep(random.random())
   print("++++++++gender is oldman")
   time.sleep(random.random())
   print("++++++++age is 48")
   mutex.release()

if __name__ == '__main__':
   mutex = Lock()  # 创建一把互斥锁
   print("创建锁了!!!!")

   p1 = Process(target=task1,args=(mutex,))
   p2 = Process(target=task2,args=(mutex,))

   p1.start()
   p2.start()

加锁 解决了安全问题 带来了效率降低的问题

锁其实只是给执行代码加了限制 本质是一个标志 为True 或False

如何使得即保证安全 又提高效率

锁的 粒度

粒度指的是被锁住的代码的多少

粒度越大锁住的越多 效率越低

 

互斥锁的案例:

抢票

def show():
   with open("db.json") as f:
       data = json.load(f)
       print("剩余票数",data["count"])

def buy():
   with open("db.json") as f:
       data = json.load(f)
       if data["count"] > 0:
           data["count"] -= 1
           with open("db.json","wt") as f2:
               json.dump(data,f2)
               print("抢票成功!")

def task(mutex):
   show()
   mutex.acquire()
   buy()
   mutex.release()

if __name__ == '__main__':
   mutex = Lock()
   for i in range(5):
       p = Process(target=task,args=(mutex,))
       p.start()

 

IPC

Inter-Process Communication

空间复用 中内存隔离开了多个进程直接不能直接交互

IPC指的就是进程间通讯

几种方式 :

1.创建一个共享文件

缺点: 效率较低

优点: 理论上交换的数据量可以非常大

适用于: 交互不频繁 且数据量较大的情况

2.共享内存 (主要方式)

缺点: 数据量不能太大

优点: 效率高

适用于: 交互频繁,但是数据量小

3.管道

管道也是基于文件的 它是单向的 编程比较复杂

4.socket

编程复杂,更适用于基于网络来交换数据

 

共享内存的第一种方式

Manger

可以为我们创建 进程间同步的容器,但是没有处理安全问题 ,所以并不常用

Queue

Queue 翻译为队列 是一种特殊的容器 特殊之处在于存取顺序为先进先出

可以帮我们完成进程间通讯

from multiprocessing import Queue

q = Queue(2) # 创建队列 并且同时只能存储2个元素
q.put(1)
q.put(2)

# q.put(3,block=True,timeout=3) # 默认是阻塞的 当容器中没有位置了就阻塞 直到有人从里面取走元素为止
print(q.get())
print(q.get())
print(q.get(block=True,timeout=3))# 默认是阻塞的 当容器中没有位置了就阻塞 直到有人存入元素为止

扩展: 栈

也是一种特殊的容器 特殊在于 存取顺序为 先进后出

函数调用栈

调用函数时 称之为 函数入栈

函数执行结束 称之为函数出栈

生产者消费者模型:

模型就是套路 就是解决某种固定问题的固定套路

 

1.守护进程  python中的守护进程 使用场景不多  了解
2.互斥锁
  互斥锁的应用案例
3.IPC
4.队列
5.生产者消费者模型
posted @ 2019-07-04 08:46  蜗牛少少  阅读(114)  评论(0编辑  收藏  举报