15.并发编程1

确认多个子进程执行完毕

import demo
from multiprocessing import Process
​
def target(i):
    print(i)
​
if __name__ == '__main__':
    p_l = []
    for i in range(5):
        p = Process(target=target,args=(i,))
        p.start()
        p_l.append(p)
    # p.join()  # 阻塞 主进程 直到子进程执行完毕
    for p in p_l:p.join()
    print('子进程已经都执行完毕了')

守护进程

有一个参数可以把一个子进程设置为一个守护进程
守护进程是随着主进程的代码结束而结束的,注意只是代码跑完,守护进程就结束,例如如上主进程sleep两秒,子进程每次sleep半秒,那么子进程运行四次后停止。
生产者消费者模型的时候
和守护线程做对比的时候
所有的子进程都必须在主进程结束之前结束,由主进程来负责回收资源

import time
from multiprocessing import Process
​
def son1(a,b):
    while True:
        print('is alive')
        time.sleep(0.5)
​
def son2():
    for i in range(5):
        print('in son2')
        time.sleep(1)
​
if __name__ == '__main__':
    p = Process(target=son1,args=(1,2))
    p.daemon = True
    p.start()      # 把p子进程设置成了一个守护进程
    p2 = Process(target=son2)
    p2.start()
    time.sleep(2)

Process对象的其他方法

import time
from multiprocessing import Process
​
def son1():
    while True:
        print('is alive')
        time.sleep(0.5)
​
if __name__ == '__main__':
    p = Process(target=son1)
    p.start()      # 异步 非阻塞
    print(p.is_alive())   # True False
    time.sleep(1)
    p.terminate()   # 异步的 非阻塞   # 手动退出  和  start对应
    print(p.is_alive())   # 进程还活着 因为操作系统还没来得及关闭进程
    time.sleep(0.01)
    print(p.is_alive())   # 操作系统已经响应了我们要关闭进程的需求,再去检测的时候,得到的结果是进程已经结束了
​
# 什么是异步非阻塞?
    # terminate​

面向对象的方式开启进程及总结

import os
import time
from multiprocessing import Process
​
class MyProcecss2(Process):
    def run(self):
        while True:
            print('is alive')
            time.sleep(0.5)
​
class MyProcecss1(Process):
    def __init__(self,x,y):
        self.x = x
        self.y = y
        super().__init__()
    def run(self):
        print(self.x,self.y,os.getpid())
        for i in range(5):
            print('in son2')
            time.sleep(1)
​
if __name__ == '__main__':
    mp = MyProcecss1(1,2)
    mp.daemon = True
    mp.start()
    print(mp.is_alive())
    mp.terminate()
    # mp2 = MyProcecss2()
    # mp2.start()
    # print('main :',os.getpid())
    # time.sleep(1)

Process类 开启进程的方式

面向函数

def 函数名:要在子进程中执行的代码
if __name__ == '__main__':
p = Process(target= 函数名,args=(参数1,))

面向对象

class 类名(Process):
	def __init__(self,参数1,参数2):   # 如果子进程不需要参数可以不写
		self.a = 参数1
		self.b = 参数2
		super().__init__()
	def run(self):
		#要在子进程中执行的代码
            
#实例化对象p
p = 类名(参数1,参数2)
    
#Process提供的操作进程的方法
p.start() 开启进程      异步非阻塞
p.terminate() 结束进程  异步非阻塞
p.join()     同步阻塞
p.isalive()  获取当前进程的状态

daemon = True 设置为守护进程,守护进程永远在主进程的代码结束之后自动结束

并发 能够做的事儿
1.实现能够响应多个client端的server
2.抢票系统

import time
import json
from multiprocessing import Process,Lock

#查票需要并发​
def search_ticket(user):
    with open('ticket_count') as f:
        dic = json.load(f)
        print('%s查询结果  : %s张余票'%(user,dic['count']))

#购票改变了数据,需要串行​,这里要加锁
def buy_ticket(user,lock):
    # with lock:
    # lock.acquire()   # 给这段代码加上一把锁
        time.sleep(0.02)
        with open('ticket_count') as f:
            dic = json.load(f)
        if dic['count'] > 0:
            print('%s买到票了'%(user))
            dic['count'] -= 1
        else:
            print('%s没买到票' % (user))
        time.sleep(0.02)
        with open('ticket_count','w') as f:
            json.dump(dic,f)
    # lock.release()   # 给这段代码解锁
​
def task(user, lock):
    search_ticket(user)
    with lock:
        buy_ticket(user, lock)
​
if __name__ == '__main__':
    lock = Lock()
    for i in range(10):
        p = Process(target=task,args=('user%s'%i,lock))
        p.start()

总结:
1.如果在一个并发的场景下,涉及到某部分内容
# 是需要修改一些所有进程共享数据资源
# 需要加锁来维护数据的安全
2.在数据安全的基础上,才考虑效率问题
3.同步存在的意义
# 数据的安全性

在主进程中实例化 lock = Lock()
把这把锁传递给子进程
在子进程中 对需要加锁的代码 进行 with lock:
# with lock相当于lock.acquire()和lock.release()
在进程中需要加锁的场景
# 共享的数据资源(文件、数据库)
# 对资源进行修改、删除操作
加锁之后能够保证数据的安全性 但是也降低了程序的执行效率

进程之间的通信

进程之间的数据隔离

from multiprocessing import Process
n = 100
def func():
    global n
    n -= 1
​
if __name__ == '__main__':
    p_l = []
    for i in range(10):
        p = Process(target=func)
        p.start()
        p_l.append(p)
    for p in p_l:p.join()
    print(n)

通信——进程之间的通信——IPC(inter process communication)
速度快
锁问题解决
IPC机制
进程彼此之间互相隔离,要实现进程间通信(IPC),
multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
共享内存空间
队列=管道+锁

from  multiprocessing import Queue

# 占用的内存,最好小数据,消息数据,下载地址
# Queue(限制队列里面的个数)
# 先进先出
q = Queue(3)
# 添加
q.put('a')
q.put('b')
q.put({'x':2})
print('-------')
# q.put('篮子满了')
print('==========')
# 队列满了,相当于锁了
# 提取
print(q.get())
print(q.get())
print(q.get())
# # 队列为空,等待加入,也会阻塞,相当于锁了
print('队列为空')
print(q.get())

生产者消费者模型

  1. 什么是生产者消费者模型
    生产者:代指生产数据的任务
    消费者:代指处理数据的任务
    该模型的工作方式:
    生产者生产数据传递消费者处理
    实现方式:
    生产者---->队列<------消费者
    厨师----》外卖小哥和外卖平台<-----消费者
    厨师不影响生产效率 不用等厨师炒完这道菜
    可以不停的炒菜 就可以点别的菜
    炒好的菜可以给
    外卖小哥
  2. 为何要用
    当程序中出现明细的两类任务,一类负责生产数据,一类负责处理数据
    就可以引入生产者消费者模型来实现生产者与消费者的解耦合,平衡生产能力与消费能力,从提升效率
  3. 如何用

方法1: Queue

	import time,random
	from  multiprocessing import  Process,Queue
	
	def producer(name,food,q):
	    for i in range(10):
	        res = '%s%s'%(food,i)
	        # 模拟生产数据的时间
	        time.sleep(random.randint(1,3))
	        q.put(res)
	        print('厨师%s生成了%s'%(name,res))
	
	def consumer(name,q):
	    while True:
	        # 订单都没了还在等,队列里面空了
	        res = q.get()
	        if res is None:
	            break
	        # 模拟处理数据的时间
	        time.sleep(random.randint(1, 3))
	        print('吃货%s吃了%s'%(name,res))

	if __name__ == '__main__':
    q= Queue()
    # 生产者
    p1 = Process(target=producer,args=('大海','包子',q))
    p2 = Process(target=producer,args=('中海','辣椒炒肉',q))
    p3 = Process(target=producer,args=('小海','土豆丝',q))
    # 消费者
    c1 = Process(target=consumer, args=('夏洛', q))
    c2 = Process(target=consumer, args=('西施', q))

    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()

    # 等待生产者生成完成
    p1.join()
    p2.join()
    p3.join()
    # 生产者生成完成
    # 还生成一个多余None给消费者
    q.put(None)
    q.put(None)
    print('主')

方法2: JoinableQueue

import time,random
from  multiprocessing import  Process,JoinableQueue

def producer(name,food,q):
    for i in range(10):
        res = '%s%s'%(food,i)
        # 模拟生产数据的时间
        time.sleep(3)
        q.put(res)
        print('厨师%s生成了%s'%(name,res))

def consumer(name,q):
    while True:
        # 订单都没了还在等,队列里面空了
        res = q.get()

        # 模拟处理数据的时间
        time.sleep(3)
        print('吃货%s吃了%s'%(name,res))
        # 每次完成队列取一次,往q.join() ,取干净了q.join()运行完
        q.task_done()



if __name__ == '__main__':
    start = time.time()
    q= JoinableQueue()
    # 生产者
    p1 = Process(target=producer,args=('大海','包子',q))
    p2 = Process(target=producer,args=('中海','辣椒炒肉',q))
    p3 = Process(target=producer,args=('小海','土豆丝',q))
    # 消费者
    c1 = Process(target=consumer, args=('夏洛', q))
    c2 = Process(target=consumer, args=('西施', q))
    # #3.守护进程的作用: 主进程死了,消费者子进程也跟着死
    #     #把消费者变成守护进程
    c1.daemon = True
    c2.daemon = True
    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()

# 等待生产者生成完成
p1.join()
p2.join()
p3.join()
# 生产者生成完成
# 菜全部上座了
# 消费者task_done给q.join()发信号
# 生产者运行完?1,2


q.join()
# 消费者吃完?1,2 但是while卡住了
# 意味着print('主')执行主进程运行完了,生产者运行完了
# 消费者也吃完了
# 盘子都空了
# 但是消费者还是阻塞,可以用守护进程结束掉子进程
print('主',time.time()-start)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值