day8 通信和线程池进程池

通信和线程池进程池

01 . 线程间通信

  • 同一个进程中的多个线程可以直接通信(一个线程可以直接使用另一个线程中产生的数据)

  • 通信原则:使用全局变量

    from threading import Thread,current_thread
    '====================方案1====================='
    def sum1(x,y):
        # z是第一个子线程定义的全局变量
        global z
        z = x + y
        print(current_thread(),a)
    
    def func2():
        print(current_thread(),z,a)
    
    
    if __name__ == '__main__':
        # a是在主线程中定义的全局变量
        a = 100
        t1 = Thread(target=sum1,args=(10,20))
        t1.start()
    
        t1.join()
    
        t2 = Thread(target=func2)
        t2.start()
    
        print('主线程:',current_thread(),z)
    
    
    '====================方案2====================='
    def dowload(name):
    
        all_data.append(f'{name}数据')
    
    
    if __name__ == '__main__':
        all_data = []
    
        # 创建子线程同时下载多个电影数据
        names = ['电影1','电影2','电影3','电影4']
        ts = []
        for name in names:
            t = Thread(target=dowload,args=(name,))
            t.start()
            ts.append(t)
    
        # 等到所有电影下载结束,在主线程中处理下载得到的数据
        for t in ts:
            t.join()
        print(all_data)
        
    '===================方案3====================='
    
    def dowload(name):
    
        # print(f'{name}数据')
        time.sleep(randint(3,7))
        # 1)添加数据
        q.put(f'{name}数据')
    
    
    if __name__ == '__main__':
    
    
        # 使用队列
        # 2) 创建队列对象
        q = Queue()
        # 创建子线程同时下载多个电影数据
        names = ['电影1', '电影2', '电影3', '电影4']
    
        for name in names:
            t = Thread(target=dowload, args=(name,))
            t.start()
    
        # 3) 获取队列中的数据
        # 队列的get操作有等待功能:如果在执行get的时候队列为空,代码不会报错,而是停留当前位置,直到队列不为空或者超时为止。
        for _ in range(4):
            print(q.get(timeout=8))
    

02 . 进程间通信

  • 不同进程中的数据无法直接共享,如果进程间想要通信(数据传递)必须使用进程队列

    • from multiprocessing import Process,Queue(进程队列,支持多进程通信)
    • from queue import Queue(这个是线程队列,不能进行进程间通信)
  • 进程队列的使用方法

    • 创建全局进程队列对像

    • 将队列对象作为参数传递到进程中,如果使用队列的进程和创建队列的进程不一致就必须要通过参数传递到队列,一致直接使用。

    • 在任意进程中使用队列获取数据

      from threading import Thread,current_thread
      from queue import Queue
      import time
      from random import randint
      from multiprocessing import Process,Queue,current_process
      
      
      def func1(queue):
          print('func1:',current_process())
          queue.put(100)
      
      def func2(queue):
          print('func2:',current_process())
          queue.put(200)
      
      def func3():
          print('func3',current_process())
          q.put(300)
      
      
      if __name__ == '__main__':
          x = 100
          all_data = []
      
          q = Queue()
          print('创建队列:',current_process())
      
          p1 = Process(target=func1,args=(q,))
          p2 = Process(target=func2, args=(q,))
          p1.start()
          p2.start()
      
          t1 = Thread(target=func3())
          t1.start()
      
          print(q.get(timeout=2))
          print(q.get(timeout=2))
          print(q.get(timeout=2))
      

03 . 队列如何正确结束

  • 创建队列,并且创建一个子线程获取队列中的数据

  • 创建多个线程同时获取多个数据

  • 等到所有的任务都完成,把队列结束标志添加到队列中

    from queue import Queue
    import time
    from random import randint
    from threading import Thread
    
    
    def dowloda(name):
        time.sleep(randint(1,10))
        q.put(f'{name}数据')
    
    
    def get_data():
        while True:
            data = q.get()
            if data == 'end':
                break
            print(data)
    
    
    if __name__ == '__main__':
        q = Queue()
        t2 = Thread(target=get_data)
        t2.start()
    
        ts = []
        for x in range(randint(30,50)):
            t = Thread(target=dowloda,args=(f'电影{x}',))
            t.start()
            ts.append(t)
    
        for t in ts:
            t.join()
    
        q.put('end')
    

04 . 线程池

  • 线程池:一个线程池中有多个线程,并且可以添加多个任务(任务的数量可以比线程的数量多),线程池会自动给线程池的线程分配任务,知道所有的任务都完成。

  • 使用线程池

    • 创建线程池:ThreadPoolExecutor(线程数)
    • 添加任务
      1. 任务一个一个的添加到线程池中:线程池对象 . submit(任务对应的函数,实参1,实参2,…)
      2. 同时添加多个任务 - 任务对应的函数有且只有一个参数 : 线程池对象 . map(函数,实参对应的序列)
  • 关闭线程池并且等待线程池的任务结束

    • 关闭线程池指的是停止向线程池中添加任务

    • 线程池关闭之前可以随时添加任务

    • 不能在线程池关闭以后添加任务

      from queue import Queue
      import time
      from random import randint
      from threading import Thread,current_thread
      
      # 导入线程池对应的类 - 线程池执行者
      from concurrent.futures import ThreadPoolExecutor
      
      
      def dowloda(name):
          time.sleep(randint(2,4))
          print(f'{name}数据')
      
      
      if __name__ == '__main__':
          names = [f'电影{x}'for x in range(50)]
      
          pool = ThreadPoolExecutor(5)
          # for x in names:
          #     pool.submit(dowloda,x)
      
          pool.map(dowloda,names)
      
          pool.shutdown()
      

05 . 进程池

  • 创建进程池对象

  • 添加任务

    • 一次添加一个任务

      # pool.apply_async(download, args=('肖申克的救赎',))
      # pool.apply_async(func1, args=(100, 200))
      # for x in range(10):
      #     pool.apply_async(download, args=(f'电影{x}',))
      
    • 同时添加多个任务

      pool.map_async(download, ['电影1', '电影2', '电影3'])
      
  • 关闭进程池(通过async方式添加的任务,必须在任务添加结束后依次执行close和join操作,任务才会启动)

    from multiprocessing import Pool, current_process
    import time
    from random import randint
    
    
    def download(name):
        time.sleep(randint(2, 6))
        print(f'{name}数据', current_process())
    
    
    def func1(x, y):
        print(x, y)
    
    
    if __name__ == '__main__':
        # 1. 创建进程池对象
        pool = Pool(5)
    
        # 2. 添加任务
        # 1) 一次添加一个任务
        # pool.apply_async(download, args=('肖申克的救赎',))
        # pool.apply_async(func1, args=(100, 200))
        # for x in range(10):
        #     pool.apply_async(download, args=(f'电影{x}',))
    
        # 2) 同时添加多个任务
        pool.map_async(download, ['电影1', '电影2', '电影3'])
    
        # 3. 关闭进程池(通过async方式添加的任务,必须在任务添加结束后依次执行close和join操作,任务才会启动)
        pool.close()
        pool.join()
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值