• 掌握并发编程2


    七、队列

      7.1、作用
        实现进程间通信(IPC)

      7.2、优点:

        1、效率高,多个进程共享一块内存数据

        2、能从复杂的锁问题中解脱出来

      7.3、参数

        maxsize  队列中允许的最大项数,省略则无大小限制
        注意:

          1、队列中存放的是消息而非大数据

          2、队列占用的是内存空间,因而 maxsize 即便无大小限制也会受限于内存大小

      7.4、方法

        q.put()  插入数据到队列中

        q.get()  从队列中读取并删除一个元素

        q.get_nowait()  取不出值报错

      7.5、队列的使用

    from multiprocessing import Process, Queue
    
    
    q = Queue(3)
    q.put(1)
    q.put(2)
    q.put(3)
    print(q.full())
    
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.empty())

    八、生产者消费者模型介绍

      8.1、生产者、消费者
        1、生产者:生产数据的任务
        2、消费者:处理数据的任务
      8.2、生产者和消费者模式

        通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据后不用等待消费者处理,

        而直接扔给阻塞队列。消费者不找生产者要数据,而是直接从阻塞队列中取。阻塞队列相当于一个缓冲区,平衡了生产者和消费者的处理能力。

      8.3、生产者消费者模型实现

    from multiprocessing import Process, Queue
    import time
    import random
    
    
    def producer(name, data, q):
        for i in range(10):
            q.put(data)
            print('%s生产了%s' % (name, data))
            time.sleep(0.1)
    
    def consumer(name, q):
        while True:
            data = q.get()
            print('%s吃了%s' % (name, data))
    
    
    
    if __name__ == '__main__':
        q = Queue()
        p1 = Process(target=producer, args=('a', '馒头', q))
        p2 = Process(target=producer, args=('b', '包子',q))
        c1 = Process(target=consumer, args=('c', q))
        c2 = Process(target=consumer, args=('d', q))
    
        p1.start()
        p2.start()
        c1.start()
        c2.start()

        以上代码主进程永远不会结束,因为列表 q 中取值完后,会一直卡在 q.get() 这一步。因此要用到新的队列。

      8.4、JoinableQueue([maxsize)]    

        8.4.1、作用

          允许项目的使用者通知项目已被成功处理,通知进程是使用共享的信号和条件变量来实现的

        8.4.2、参数

          maxsize    队列中允许的最大项数,省略则无大小限制

        8.4.3、方法

          q.task_done()  使用者用此方法发出信号,表示 q.get() 的返回项目已经被处理。如果调用此方法的次数大于队列中删除项目的数量,将引发 ValueError 异常。

          q.join()     生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用 q.task_done() 方法为止。

        8.4.4、基于 JoinableQueue 实现生产者模型

    from multiprocessing import Process, JoinableQueue
    import time
    
    
    def producer(name, data, q):
        for i in range(10):
            q.put(data)
            print("%s生产了%s" % (name, data))
            time.sleep(0.5)
    
    def consumer(name, q):
        while True:
            data = q.get()
            print('%s吃了%s' % (name, data))
            q.task_done()
    
    if __name__ == '__main__':
        q = JoinableQueue()
        p1 = Process(target=producer, args=('a', '包子', q))
        p2 = Process(target=producer, args=('b', '馒头', q))
        c1 = Process(target=consumer, args=('c', q))
        c2 = Process(target=consumer, args=('d', q))
    
        p1.start()
        p2.start()
        c1.daemon = True
        c2.daemon = True
        c1.start()
        c2.start()
        p1.join()
        p2.join()
    
        q.join()

    九、线程理论

      9.1、进程用来把资源集中到一起,是资源集合。线程是CPU上的执行单位。

        特点:

          1、同一进程内的多个线程共享该进程的地址资源
          2、创建线程的开销要远远小于创建进程的开销

      9.2、开启线程的两种方式

        1、利用类名里面传 target,args 参数来开设线程

    from threading import Thread
    import time
    
    
    def task(name):
        print('%s is running' % name)
        time.sleep(3)
        print('%s is studying' % name)
    
    if __name__ == '__main__':
        t = Thread(target=task, args=('a'))
        t.start()
        print('')

        2、自定义线程类,定义暴露的接口 run 方法  

    class My_thread(Thread):
        def __init__(self, name):
            super().__init__()
            self.name = name
    
        def run(self):
            print('%s is studying' % self.name)
            time.sleep(3)
            print('%s is sleeping' % self.name)
    
    
    if __name__ == '__main__':
        t = My_thread('a')
        t.start()
        print('')

        9.3、多线程与多进程的区别
          1、开启速度

            线程的创建开销极小

            开启进程的信号发送给操作系统后,操作系统申请内存空间,然后拷贝父进程地址空间到子进程,开销远大于线程

          2、pid

            在主进程下开启多个线程,每个线程都跟主进程 pid 一样

            开多个进程时,每个进程的 pid 都不一样

          3、同一进程内的线程共享该进程的数据

    十、Thread 对象的其他属性或方法

      10.1、Thread 实例对象的方法

        isAlieve()  返回线程是否是活动的

        getName()     返回线程名

        setName()     设置线程名

      10.2、threading 模块提供的一些方法

        threading.currentThread() 返回当前的线程变量 

        threading.enumerate()    返回一个包含正在运行的线程的 list 。正在运行指线程启动后和结束前。  

        threading.active_count()  返回正在运行的线程数量,与 len(threading.enumerate()) 有相同结果。
     

    from threading import Thread
    import threading
    import time
    
    def work():
        time.sleep(3)
        print(threading.current_thread().getName())
    
    def study():
        print('123')
        time.sleep(2)
        print(threading.current_thread().getName())
    
    
    if __name__ == '__main__':
        t = Thread(target=work)
        t2 = Thread(target=study)
        t.start()
        t2.start()
    
        print(threading.current_thread().getName())
        print(threading.current_thread())
        print(threading.enumerate())
        print(threading.active_count())
        print('')
    123
    MainThread
    <_MainThread(MainThread, started 11572)>
    [<_MainThread(MainThread, started 11572)>, <Thread(Thread-1, started 15224)>, <Thread(Thread-2, started 8576)>]
    3
    zhu
    Thread-2
    Thread-1

    十一、守护线程

      11.1、与守护进程的区别

        1、守护进程:主进程的代码运行结束后就算作运行完毕,守护进程被回收,然后主进程等待非守护子进程运行结束,并回收资源,最后主进程结束。

        2、守护线程:主线程在非守护线程运行完毕后算作运行完毕,守护线程被回收,

    十二、线程互斥锁

      原理与进程互斥所一样
      1、加锁前,输出为 9

    from threading import Thread
    import time
    
    n = 10
    def task():
        global n
        tmp = n
        time.sleep(0.5)
        n = tmp - 1
    
    t_list = []
    for i in range(10):
        t = Thread(target=task)
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(n)

      2、加锁后,输出为 0

    from threading import Thread, Lock
    import time
    
    n = 10
    def task(mutex):
        mutex.acquire()
        global n
        tmp = n
        time.sleep(0.5)
        n = tmp - 1
        mutex.release()
    
    t_list = []
    mutex = Lock()
    for i in range(10):
        t = Thread(target=task, args=(mutex,))
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(n)

       

        


      

  • 相关阅读:
    写一个精确定位异常的方法
    做一个牛XX的身份证号验证类(支持15位和18位)
    C#获取设备的IP和Mac类
    winfrom 倒计时控件
    一个实用价值很大的人脸关键点检测算法PFLD
    刷新WIDER Face纪录!TinaFace:人脸检测新网络,代码已开源!
    虚拟机安装教程
    python---文件路径的操作(有点意思)
    python_opencv -------->>>>>>>>>cv2.warpAffine()参数详解
    yolov5数据增强引发的思考——透视变换矩阵的创建
  • 原文地址:https://www.cnblogs.com/binyuanxiang/p/11343450.html
Copyright © 2020-2023  润新知