• DAY 34 进程通信、消费者模型和线程


    一.进程间通行

      队列:先进先出

      堆栈:先进后出

      一般利用队列实现进程间的通信

    from multiprocessing import Queue
        q = Queue(5) # 产生一个最多能够存放五个数据的队列
    
        q.put(1) # 往队列中存放数据,
                 # 如果存放的数据个数大于队列最大存储个数,程序会阻塞 
    
        print(q.full) # 判断队列是否饱和
        
        q.get() # 取数据,get一次就取一个
    
        q.get_nowait() # 在队列有数据的情况下,与get取值相同
                       # 在队列没有数据的情况下,取值直接报错
    
        print(q.empty()) # 判断队列是否为空,在并发情况下,判断不准确
    
        print(q.get()) # 如果队列为空,get就会在原地等待队列中有数据过来

    二.基于队列实现进程间通信

    from multiprocessing import Queue, Process
        
    def producer(q):
        q.put('hello world')
    
    
    def consumer(q):
        print(q.get())
    
    
    if __name__ =='__main__':
        q.Queue() # 生成一个队列对象
        p1 = Process(target=producer,args=(q,))
        c1 = Process(target=consumer,args=(q,))
        p1.start()
        c1.start()

    三.生产者消费者模型

      生产者消费者模型:

        生产者: 生产数据的程序

        消费者: 处理数据的程序

      解决供需不平衡的问题

        定义一个队列,用来存放固定数量的数据

        解决一个生产者和消费者不需要直接交互,两者通过队列进行数据传输

      Queue(队列) = 管道 + 锁

      1.Queue方法

    from multiprocessing import Process,Queue,JoinableQueue
    import time
    import random
    
    def produce(name,food,q):
        for i in range(5):
            data = '%s 做了 %s%s' % (name,food,i)
            time.sleep(random.randint(1,3))
            print(data)
            q.put(data) # 将生产的数据放入队列中
    
    
    def consumer(name,q):
        while True:
            data:str = q.get() 
            if data is None:break
            time.sleep(random.randint(1,3))
            data = data.replace('', '')
            print('%s 吃了 %s' % (name, data))
    
    
    if __name__ == '__main__':
        q = Queue() # 生成一个队列对象
        p1 = Process(target=produce,args=('egon', '包子', q,))
        p2 = Process(target=produce,args=('tank', '小笼', q,))
        c1 = Process(target=consumer,args=('owen', q,))
        c2 = Process(target=consumer,args=('jason', q,))
        p1.start()
        p2.start()
        c1.start()
        c2.start()
        p1.join() # 等待生产者生产完所有的数据
        p2.join() # 等待生产者生产完所有的数据
        # 在生产者生产完数据之后,往队列里面放一个提示性的消息,告诉消费者已经没有数据,你走吧,不要等了
        #q.put(None)
        #q.put(None)
      
      

    2.JoinableQueue方法

    from multiprocessing import Process, JoinableQueue
    import time
    import random
    
    
    def produce(name, food, q):
        for i in range(5):
            data = '%s 做了 %s%s' % (name, food, i)
            time.sleep(random.randint(1, 3))
            print(data)
            q.put(data)  # 将生产的数据放入队列中
    
    
    def consumer(name, q):
        while True:
            data: str = q.get()
            if data is None: break
            time.sleep(random.randint(1, 3))
            data = data.replace('', '')
            print('%s 吃了 %s' % (name, data))
            q.task_done()  # 告诉你的队列,你已经将数据取出并且处理完毕
    
    
    if __name__ == '__main__':
        q = JoinableQueue()  # 生成一个队列对象
        p1 = Process(target=produce, args=('egon', '包子', q,))
        p2 = Process(target=produce, args=('tank', '小笼', q,))
        c1 = Process(target=consumer, args=('owen', q,))
        c2 = Process(target=consumer, args=('jason', q,))
        p1.start()
        p2.start()
        c1.daemon = True
        c2.daemon = True
        c1.start()
        c2.start()
        # 等待生产者生产完所有的数据
        p1.join()
        p2.join()
        q.join()  # 等待队列中数据全部取出

    四.线程

      1.什么是线程

        进程:资源单位(只申请内存空间)

        线程:执行单位(执行代码)

        注意: 每一个进程中都会自带一个线程

      2.为什么要有线程

        开启一个进程:

          申请内存空间 耗时

          将代码拷贝到申请的内存空间中 耗时

        开启一个线程

          不需要申请内存空间 速度快

          不需要拷贝代码 省时  

        总结:开线程的开销远远小于进程的开销!!!

    五.开启线程的两种方式

      1.Thread模块开始线程

    from threading import Thread
    import time
    
    
    def task(name):
        print('%s is running' % name)
        time.sleep(1)
        print('%s is running' % name)
    
    
    t = Thread(target=task,args=('egon',))
    t.start()
    print('')

    2.自定义模块继承Thread模块开始线程

    from threading import Thread
    import time
    
    
    class MyThread(Thread):
        def __init__(self,name):
            super().__init__() # 重写功能,以防父类功能缺少执行
            self.name = name
    
        def run(self):
            print('%s is running' % self.name)
            time.sleep(1)
            print('%s is running' % self.name)
    
    
    t = MyThread('egon')
    t.start()
    print('')

    六.线程之间数据共享

    join只能将整体进行串行,人为的规定顺序。

    from threading import Thread
    
    x = 100
    
    
    def task():
        global x
        x = 1
    
    
    t = Thread(target=task)
    t.start()
    t.join()
    print(x)

    七.线程互斥锁

    互斥锁同一时间只有一个线程能运行,把并行变成串行,为了保证数据的安全性。从而降低了效率。

    互斥锁可以将局部变成串行让大家公平的抢

    from threading import Thread, Lock
    import time
    
    x = 100
    mutex = Lock()
    
    
    def task():
        global x
        mutex.acquire()
        temp = x
        time.sleep(0.1)
        x = temp - 1
        mutex.release()
    
    
    t_list = []
    for i in range(100):
        t = Thread(target=task)
        t_list.append(t)
        t.start()
    
    for i in t_list:
        i.join()
    
    print(x)

    八.线程对象其他属性和方法

    from threading import Thread, active_count, current_thread
    import os, time
    
    
    def task():
        print('%s is running' % current_thread().name,os.getpid())
        time.sleep(1)
        print('%s is done' % os.getpid())
    
    
    t = Thread(target=task)
    t.start()
    print(active_count())
    print('', os.getpid(),current_thread().name)

    九.守护线程

    大前提:一个任务守护另外一个任务代码的执行过程

    在一个进程内只有一个线程的情况下,守护进程会在主进程代码执行完毕后立刻结束

    在一个进程可以开启多个线程,守护的线程会在该进程内所有非守护线程都执行完之后才结束

    from threading import Thread
    import time
    
    
    def task():
        print('is running')
        time.sleep(2)
        print('is over')
    
    
    t = Thread(target=task)
    t.daemon = True
    t.start()
    print('')
  • 相关阅读:
    设计模式:迭代器模式
    设计模式:观察者模式
    设计模式:解释器模式
    设计模式:策略模式
    设计模式:状态模式
    设计模式:代理模式
    strtok函数
    人们眼中的程序员
    如何用C语言获取文件的大小
    C++著名库的比较和学习经验
  • 原文地址:https://www.cnblogs.com/zhengyuli/p/10828141.html
Copyright © 2020-2023  润新知