Python Day 32 并发编程 (守护进程, 进程同步(multiprocessing.Lock、multiprocessing.Semaphore、multiprocessing.Event) 进程间通信 multiprocessing.Queue)

守护进程

注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止(主进程和子进程是异步的),当主进程停止,该守护进程不在继续执行.守护进程也是一种子进程.

主进程创建守护进程

  其一:守护进程会在主进程代码执行结束后就终止.(但本质上是在主进程结束之前结束的,主进程需要负责回收资源)

  其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children

from multiprocessing import Process
import time
import os

def func(num):
    print(f'{num},pid:{os.getpid()},ppid:{os.getppid()}')
    while True:
        print('is alive')
        time.sleep(0.5)

def wahaha():
    i = 0
    while i < 5:
        i += 1
        print(f'第{i}秒')
        time.sleep(1)


if __name__ == '__main__':
    Process(target=wahaha).start()  #子进程在主进程结束后仍然正常执行
    p = Process(target=func,args=(1,))
    p.daemon = True #主进程结束,该守护进程结束
    p.start()
    time.sleep(3)
    print(f'pid:{os.getpid()},ppid:{os.getppid()}')
    print('主进程结束')
=============================
第1秒
1,pid:8200,ppid:2000
is alive
is alive
第2秒
is alive
is alive
第3秒
is alive
is alive
pid:2000,ppid:7244
主进程结束
第4秒
第5秒
创建守护进程

多进程中的方法

  p = Process(target=func,args=(1,)) #创建一个进程对象

       p.start()  #启动一个进程

  p.daemon = True #设置进程为守护进程,随主进程结束而结束.

  p.is_alive() #判断进程是否存活,返回bool值

  p.terminate() #发送给操作系统指令,关闭进程

from multiprocessing import Process
import time
import os

def func(num):
    print(f'{num},pid:{os.getpid()},ppid:{os.getppid()}')
    while True:
        print('is alive')
        time.sleep(0.5)

def wahaha():
    i = 0
    while i < 10:
        i += 1
        print(f'第{i}秒')
        time.sleep(1)


if __name__ == '__main__':
    p2 = Process(target=wahaha)
    p2.start()
#
    p = Process(target=func,args=(1,))
    p.daemon = True #主进程结束,该子进程结束
    p.start()
    time.sleep(3)
    print(p.is_alive())
    print(p2.is_alive())
    p2.terminate()
    time.sleep(0.1)
    print(p.is_alive())
    print(p2.is_alive())
    print(f'pid:{os.getpid()},ppid:{os.getppid()}')
    print('主进程结束')
    p2.join()
Process方法

进程同步(multiprocessing.Lock、multiprocessing.Semaphore、multiprocessing.Event) 

锁 multiprocessing.Lock (*****) 

  避免同一段代码被多个进程同时执行

  lock = Lock()  创建锁对象

  lock.acquire()  查询钥匙,如果有就拿走,如果没有就等待

  lock.release()  归还钥匙

  lock可以使用with上下文进行管理(类似于文件读取)

  with lock:

    print('hello' )

维护数据的安全
降低了程序的效率
所有的效率都是建立在数据安全的角度上的
但凡涉及到并发编程都要考虑数据的安全性
我们需要在并发部分对数据修改的操作格外小心,如果会涉及到数据的不安全,就需要进行加锁控制

lock acquire release的另外一种用法
lock 内部实现了进程之间的通信,使得谁acquire了谁release了能够在多个拥有lock参数的子进程中透明
Lock
from multiprocessing import Lock
lock = Lock()  #创建一个锁对象
lock.acquire() #想拿钥匙,如果有就拿,没有就一直等
print('拿到要钥匙了1')
lock.release() #还钥匙
lock.acquire() #想拿钥匙
print('拿到要钥匙了2')
lock.release() #还钥匙
开启一个进程锁
#db文件内容  {"count": 0}

import json
import time
from multiprocessing import Process,Lock
def search(i):
    f =open('db')
    ticket_dic =json.load(f)
    f.close()
    print(f"{i} 正在查票,剩余票数{ticket_dic['count']}")

def buy(i):
    with open('db') as f: ticket_dic = json.load(f)
    time.sleep(0.2)
    if ticket_dic['count'] > 0:
        ticket_dic['count'] -= 1
        print(f'{i} 买到票了')
        time.sleep(0.2)
        with open('db','w') as f :json.dump(ticket_dic,f)
    else:
        print(f"{i} 太火爆被抢购一空了,剩余票数{ticket_dic['count']}")


# def get_ticket(i,lock):
#     search(i)
#     lock.acquire()
#     buy(i)
#     lock.release()

def get_ticket(i,lock):
    search(i)
    with lock:
        buy(i)

if __name__ == '__main__':
    lock = Lock()
    for i in range(10):
        p = Process(target=get_ticket,args=(i,lock))
        p.start()
火车票查询购买

信号量(标志True False) multiprocessing.Semaphore(***)  (锁+计数器)

  有多个钥匙的锁

  sem = Semaphore(4)  创建锁对象,4把钥匙,可以被连续acquire4次

  sem.acquire()  查询钥匙,如果有就拿走,如果没有就等待

  sem.release()  归还钥匙

  sem 可以使用with上下文进行管理(类似于文件读取)

  with sem:

    print('hello' )

from multiprocessing import Semaphore
sem = Semaphore(4) #4把钥匙
sem.acquire()
print(1)
sem.acquire()
print(2)
sem.release()
sem.acquire()
print(3)
sem.acquire()
print(4)
sem.acquire()
print(5)
sem.acquire()
print(6)
Semaphore(4)
from multiprocessing import Semaphore,Process
import time
import random

# def ktv(sem,i):
#     sem.acquire()
#     print(f'{i}走进ktv')
#     time.sleep(random.randint(1,3))
#     print(f'{i}走出ktv')
#     sem.release()

def ktv(sem,i):
    with sem:
        print(f'{i}走进ktv')
        time.sleep(random.randint(1,3))
        print(f'{i}走出ktv')


if __name__ == '__main__':
    sem = Semaphore(4)
    for i in range(10):
        p = Process(target=ktv,args=(sem,i))
        p.start()
唱吧 ktv

事件 multiprocessing.Event(**)

  控制子进程执行还是阻塞的一个机制

  e = Event()  创建一个事件对象

Event方法  在事件中有一个信号(标志)

  wait()   如果这个标志是True wait的执行效果就是pass ,如果是False,wait方法的效果就是阻塞,直到这个标志变成True

  控制标志方法

    is_set()  判断标志的状态,返回bool值

    set()  将标志设置为True

    clear()  将标志设置为False

from multiprocessing import Event
e = Event() #阻塞,事件的创建之初标志的状态是False
print(e.is_set())
e.set() #将标志改为True
print(e.is_set())
e.wait() #当标志为True是pass,不阻塞
创建一个事件
from multiprocessing import Event,Process
import time

def func1(e):
    print('start func1')
    print(e.is_set())  #事件创建之初是False
    e.wait(1)  #不修改状态(网络测试,发送短信,发送邮件),超时后继续执行,不继续阻塞
    print(e.is_set())  
    e.wait()  #持续阻塞
    print(e.is_set()) #主进程3(异步)s后修改信号标志为True ,继续执行
    print('end func1')

if __name__ == '__main__':
    e = Event()
    Process(target=func1,args=(e,)).start()
    time.sleep(3)
    e.set()
事件的控制
from multiprocessing import Event,Process
import time
import random

def tarffic_light(e):
    while True:
        while e.is_set():
            print('\033[1;32m绿灯亮\033[0m')
            time.sleep(2)
            e.clear()
        else:
            print('\033[1;31m红灯亮\033[0m')
            time.sleep(2)
            e.set()


def car(i,e):
    while not e.is_set():
        print(f'{i}正在等待通过...')
        e.wait()
    else:
        print(f'{i}通过.')

if __name__ == '__main__':
    e = Event()
    light = Process(target=tarffic_light,args=(e,))
    light.daemon =True
    light.start()
    car_list = []
    for i in range(1,21):
        p = Process(target=car,args=(i,e))
        car_list.append(p)
        p.start()
        time.sleep(random.randint(0,3))
    for i2 in car_list:i2.join()  #控制子进程先执行完毕
    print('执行完啦')
while版红绿灯
import time
import random
from multiprocessing import Process,Event
def traffic_light(e):
    print('\033[1;31m红灯亮\033[0m')
    while True:
        time.sleep(2)
        if e.is_set():
            print('\033[1;31m红灯亮\033[0m')
            e.clear()
        else:
            print('\033[1;32m绿灯亮\033[0m')
            e.set()

def car(i,e):
    if not e.is_set():
        print('car%s正在等在通过'%i)
        e.wait()
    print('car%s通过'%i)

if __name__ == '__main__':
    e = Event()
    light = Process(target=traffic_light,args=(e,))
    light.daemon = True
    light.start()
    car_lst = []
    for i in range(20):
        p = Process(target=car,args=(i,e))
        p.start()
        time.sleep(random.randint(0,3))
        car_lst.append(p)
    for car in car_lst:car.join()
if 红绿灯

说明:红绿灯的的变化和汽车的通行是两个独立的进程,汽车通过对红绿灯的事件信号的查询判断等待和放行,每一个汽车都是独立的进程

进程间通信(进程之间数据共享)

  进程间通信 IPC(Inter-Process Communication)

队列 multiprocessing.Queue  (先进先出)

  q =Queue()  创建一个队列   q = Queue(5) 队列长度为5

  q.put(1)  向队列中放一个数据,可以是int list dict ... 当队列满时会阻塞

  q.get()  从队列中获取一个数据  没有值会一直阻塞

  q.empty()  判断队列是否为空 返回bool值   多进程时不准

  q.full()  判断队列是否已满 返回bool值  多进程时不准

q = Queue(3)
try:
    q.get_nowait()
except:
    print('队列中没有值')
q.get_nowait()
q = Queue(3)
q.put(1)
q.put('aaa')
q.put([1,2,3])
# q.put('alex')   #队列满会阻塞
try:
    q.put_nowait('alex')
except:
    print('丢失了一个数据')
q.put_nowait()
创建一个队列
from multiprocessing import Process,Queue
def func(num,q):
    q.put({num:num**num})

if __name__ == '__main__':
    q = Queue()
    # p = Process(target=func, args=(10,q))
    # p.start()
    # print(q.get())
    for i in range(10):
        p = Process(target=func,args=(i,q))
        p.start()
    for i in range(10):
        print(q.get())


=============
{0: 1}
{1: 1}
{3: 27}
{4: 256}
{2: 4}
{5: 3125}
{9: 387420489}
{8: 16777216}
{6: 46656}
{7: 823543}
使用Queue队列特性使用put,get解决返回值问题
生产者消费者模型
包子的故事

效率问题

生产者 托盘 消费者


猜你喜欢

转载自www.cnblogs.com/eailoo/p/9174257.html