并发编程

1、进程锁

一、使用锁维护执行顺序
代码:
    from multiprocessing import Process,Lock
    import os
    import time

    def task(i,lock):
        # 开始上锁
        lock.acquire()
        print('第%s个:进程id号:%s进来了'%(i,os.getpid()))
        time.sleep(3)
        print('第%s个:进程ID号:%s走了'%(i,os.getpid()))
        # 释放锁
        lock.release()

    if __name__ == '__main__':
        lock = Lock()   # 共用一把锁
        for i in range(5):
            p = Process(target=task,args=(i,lock))
            p.start()
# 上面这种情况虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。

2、进程间数据隔离

一、进程之间数据是互不影响的
代码:
    from multiprocessing import Process
    n = 10

    def task():
        global n
        n = 100
        print('task:',n)

    if __name__ == '__main__':
        # task()
        p =Process(target=task)
        p.start()
        print('main',n)
    # 注:加上task()输出结果为main 10,task: 100
        # 不加task()输出结果为main 10,task: 100

3、Queue队列的使用

一、方法介绍:
    1.Queue([maxsize]):创建共享的进程队列。maxsize是队列允许的最大项数。如果不写参数的话。
    2.q.get([block[,timeout]]):返回q中的一个项目。如果为空,此方法将造成堵塞,直到有可用项目为止。
    3.q.get_nnowait():和q.get(False)方法一样,作用是控制堵塞:# q.put('my is handsome4', block=False)
    4.q.put(item[,block[,timeout]]):将item放入队列
    5.q.qsize():返回队列中目前项目的正确数量。
    6.q.empty():如果队列里面放数据返回Fales,不放数据返回True,结果可能是不可靠的。
    7.q.full():如果队列已满,返回True,结果可能是不可靠的
二、方法里的参数
    1.如:q.get( [ block [ ,timeout ] ] ):返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。block用于控制阻塞行为,默认为True. 如果设置为False,将引发Queue.Empty异常(定义在Queue模块中)。timeout是可选超时时间,用在阻塞模式中。如果在制定的时间间隔内没有项目变为可用,将引发Queue.Empty异常。
    2.用法如下:
代码:	
from multiprocessing import Queue

if __name__ == '__main__':
    q = Queue(3)  # 拿到一个空队列的对象
    q.put('my is handsome1') # 把数据放到队列中
    q.put('my is handsome2')
    q.put('my is handsome3')
    q.put('my is handsome4', block=False)  # block用于控制阻塞行为,如果设置为False,将引发Queue.Empty异常
    q.put('my is handsome4', timeout=2)  # 如果在制定的时间间隔内没有项目变为可用,将引发Queue.Empty异常。
    q.put_nowait('my is handsome4')  # 跟block方法一样的效果

    print(q.get())
    print(q.get()) # 返回q中的数据
    print(q.get())
    print(q.get(timeout=2))  # 也有队列的属性
    print(q.get_nowait())
    print(q.qsize()) # 返回队列中目前项目的正确数量
    print(q.empty()) # 队列里面放数据返回Fales,不放数据返回True,结果可能是不可靠的
    print(q.full()) # 队列已满,返回True,结果可能是不可靠的

4、解决进程间数据隔离问题

代码:
from multiprocessing import Process,Queue

def task(queue):
    queue.put('hello') # 通过q.get()拿到的数据
    print('hi')   # 通过子进程得到的结果


if __name__ == '__main__':
    q = Queue()
    p =Process(target=task,args=(q, ))
    p.start()

    print(q.get()) # 通过主进程拿到“hello”数据
    输出结果:hi ,hello

5、生产者消费者模型代码演示

​ 在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

5.1、为什么要使用生产者和消费者模式

	在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

5.2、什么是生产者消费者模式

    生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

5.3、代码演示

版本1:取完包子遇到阻塞,直到有可用项目为止

from multiprocessing import Process, Queue
import os
import time

# 版本1:取完包子遇到阻塞,直到有可用项目为止
def producer(queue):
    for i in range(5):
        data = ('%s:蒸了第%s个包子' % (os.getpid(), i))
        print(data)
        queue.put(data)  # 把数据放入队列

def consumer(queue):
    while True:
        data = queue.get()
        print(data)

if __name__ == '__main__':
    q = Queue()
    p = Process(target=producer, args=(q,))
    p.start()

    p1 = Process(target=consumer, args=(q,))
    p1.start()

版本2:

def producer(queue):
    for i in range(5):
        data = ('%s:蒸了第%s个包子' % (os.getpid(), i))
        print(data)
        queue.put(data)  # 把数据放入队列
    queue.put(None)

def consumer(queue):
    while True:
        data = queue.get()
        if not data:break
        time.sleep(1)
        print(data)

if __name__ == '__main__':
    q = Queue()
    p = Process(target=producer, args=(q,))
    p.start()

    p1 = Process(target=consumer, args=(q,))
    p1.start()

版本3: 多生产者,少消费者

def producer(queue,food):
    for i in range(5):
        data = ('%s:生产了第%s个%s' % (os.getpid(), i,food))
        # print(data)
        queue.put(data)  # 把数据放入队列


def consumer(queue):
    while True:
        data = queue.get()
        if not data:break
        time.sleep(0.2)
        print(data)

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer, args=(q,'馒头'))
    p2 = Process(target=producer, args=(q,'花卷'))
    p3 = Process(target=producer, args=(q,'烧麦'))
    p1.start()
    p2.start()
    p3.start()

    p4 = Process(target=consumer, args=(q,))
    p5 = Process(target=consumer, args=(q,))
    p4.start()
    p5.start()
    p1.join()  # 加上join
    p2.join()  # 加上join
    p3.join()  # 加上join
    q.put(None) # 这里放几个取决于消费者有几个
    q.put(None)
    print('=====>')

版本四:最终版本:消费者多,生产者少

def producer(queue,food):
    for i in range(5):
        data = ('%s:生产了第%s个%s' % (os.getpid(), i,food))
        # print(data)
        queue.put('第%s个%s'%(i,food))  # 把数据放入队列

def consumer(queue,name):
    while True:
        try:
            data = queue.get(timeout=3)
            if not data:break
            time.sleep(0.2)
            print('消费者:%s,消费了:%s'%(name,data))
        except Exception as e:
            print(e)
            break

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer, args=(q,'馒头'))
    p2 = Process(target=producer, args=(q,'花卷'))
    p3 = Process(target=producer, args=(q,'烧麦'))
    p1.start()
    p2.start()
    p3.start()

    p4 = Process(target=consumer, args=(q,'迪迦'))
    p5 = Process(target=consumer, args=(q,'琦玉'))
    p6 = Process(target=consumer, args=(q,'悟空'))
    p7 = Process(target=consumer, args=(q,'路飞'))
    p4.start()
    p5.start()
    p6.start()
    p7.start()
    p1.join()  # 加上join
    p2.join()  # 加上join
    p3.join()  # 加上join
    q.put(None) # 这里放几个取决于消费者有几个
    q.put(None)
    print('=====>')
posted @ 2021-09-01 19:40  迷恋~以成伤  阅读(35)  评论(0)    收藏  举报