zoukankan      html  css  js  c++  java
  • Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁

    Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁

    1. 生产消费者模型

    • 定义:编程思想,模型,设计模式,理论等等,都是一种编程的方法,遇到类似的情况,套用即可.

    • 生产者消费者模型三要素:

      生产者: 产生数据的

      消费者: 接收数据做进一步处理的

      容器: 队列,起到缓冲的作用,平衡生产力与消费力,解耦.

    • 代码示例:

      from multiprocessing import Process
      from multiprocessing import Queue
      import time
      import random
      
      def producer(q,name):
          for i in range(1,6):
              time.sleep(random.randint(1,2))
              res = f'{i}号包子'
              q.put(res)
              print(f'生产者{name} 生产了{res}')
      
      def consumer(q,name):
          while 1:
              try:
                  food = q.get(timeout=3)
                  time.sleep(random.randint(1, 3))
                  print(f'33[31;0m消费者{name} 吃了{food}33[0m')
              except Exception:
                  return
      
      if __name__ == '__main__':
          q = Queue()
          p1 = Process(target=producer,args=(q,'张三'))
          p2 = Process(target=consumer,args=(q,'李四'))
          p1.start()
          p2.start()
      

    2. 线程的理论知识

    • 什么是线程

      标准描述开启一个进程:开启一个进程:进程会在内存中开辟一个进程空间,将主进程的资料数据全部复制一份,线程会执行里面的代码.

      ***进程是资源单位, 线程是执行单位;是操作系统调度的最小单元,是进程中的实际运作单位.

    • 线程vs进程

      1. 开启进程的开销非常大,比开启线程的开销大很多.
      2. 开启线程的速度非常快.要快几十倍到上百倍.
      3. 同一进程内线程与线程之间可以共享数据,进程与进程之间需借助队列等方法实现通信.
    • 线程的应用

      单个进程开启三个线程.并发的执行任务.

      并发:一个cpu 看起来像是同时执行多个任务.

    • 主线程子线程没有地位之分

      一个主线程在干活,当干完活了,得等待其他线程干完活之后,才能结束本进程.

    3. 开启线程的两种方式

    • 方式一

      from threading import Thread
      import time
      
      def task(name):
          print(f'{name} is running')
          time.sleep(1)
          print(f'{name} is gone')
      
      if __name__ == '__main__':
      
          t1 = Thread(target=task,args=('张三',))  # args的参数一定要是元组
          t1.start()
          print('===主线程')  # 线程是没有主次之分的.
      
    • 方式二

      from threading import Thread
      import time
      
      class MyThread(Thread):
          def __init__(self,name,l1,s1):
              super().__init__()
              self.name = name
              self.l1 = l1
              self.s1 = s1
          def run(self):
              print(f'{self.name} is running')
              time.sleep(1)
              print(f'{self.name} is gone')
      
      if __name__ == '__main__':
          t1 = MyThread('张三', [1,2,3], '180')
          t1.start()
          print('=====主线程')
      

    4. 线程、进程对比代码验证

    • 开启速度对比

      # 多进程
      from threading import Thread
      from multiprocessing import Process
      import os
      
      def work():
          print('hello')
      
      if __name__ == '__main__':
          t=Process(target=work)
          t.start()
          print('主线程/主进程')
          
      # 多线程
      from threading import Thread
      import time
      
      def task(name):
          print(f'{name} is running')
          time.sleep(1)
          print(f'{name} is gone')
      
      if __name__ == '__main__':
          t1 = Thread(target=task,args=('张三',))
          t1.start()
          print('===主线程')
          
      # 结论:
      # 多进程是先打印的'主线程/主进程',多线程是先打印的'张三 is running',所以得出线程的开启速度比进程快
      
    • 对比pid

      # 多进程
      from multiprocessing import Process
      import time
      import os
      
      def task(name):
          print(f'子进程: {os.getpid()}')
          print(f'主进程: {os.getppid()}')
          
      if __name__ == '__main__':
          p1 = Process(target=task,args=('张三',))  # 创建一个进程对象
          p2 = Process(target=task,args=('李四',))  # 创建一个进程对象
          p1.start()
          p2.start()
          print(f'==主{os.getpid()}')
      
      # 多线程
      from threading import Thread
      import os
      
      def task():
          print(os.getpid())
          
      if __name__ == '__main__':
          t1 = Thread(target=task)
          t2 = Thread(target=task)
          t1.start()
          t2.start()
          print(f'===主线程{os.getpid()}')
      
      # 结论:
      # 线程没有pid,进程才有pid
      
    • 共享数据的对比,同一个进程内线程共享内部数据

      from threading import Thread
      import os
      
      x = 3
      def task():
          global x
          x = 100
      
      if __name__ == '__main__':
          t1 = Thread(target=task)
          t1.start()
          t1.join()
          print(f'===主线程{x}')
          
      # 同一进程内的资源数据对于这个进程内的多个线程来说是共享的.
      

    5. 线程的其他方法

    • 代码示例:

      from threading import Thread
      from threading import currentThread
      from threading import enumerate
      from threading import activeCount
      import os
      import time
      
      def task():
          print(currentThread())  # 获取当前线程对象
          time.sleep(1)
          print('666')
          
      if __name__ == '__main__':
          t1 = Thread(target=task,name='线程1')  # name 设置线程名
          t2 = Thread(target=task,name='线程2')
          t1.start()
          t2.start()
          time.sleep(2)
          print(t1.isAlive())  # 判断线程是否活着
          print(t1.getName())  # 获取线程名
          t1.setName('子线程-1')  # 设置线程的名称
          print(t1.name)   # 获取线程名  ***
      
          # threading方法
          print(currentThread())  # 获取当前线程的对象
          print(enumerate())  # 返回一个列表,包含所有的线程对象
          print(activeCount())  # 获取当前线程存活个数 ***
          print(f'===主线程{os.getpid()}')
      

    6. 线程join

    • join: 阻塞 告知主线程要等待我子线程执行完毕之后再执行主线程

    • 代码示例:

      from threading import Thread
      import time
      
      def task(name):
          print(f'{name} is running')
          time.sleep(1)
          print(f'{name} is gone')
      
      if __name__ == '__main__':
          start_time = time.time()
          t1 = Thread(target=task,args=('张三',))
          t2 = Thread(target=task,args=('李四',))
          t3 = Thread(target=task,args=('王五',))
      
          t1.start()
          t1.join()
          t2.start()
          t2.join()
          t3.start()
          t3.join()
      
          print(f'===主线程{time.time() - start_time}')  # 线程是没有主次之分的.
      

    7. 守护线程

    • 守护线程:等待非守护子线程以及主线程结束之后,结束.

    • 代码示例:

      示例一:简单使用守护线程

      from threading import Thread
      import time
      
      def sayhi(name):
          print('你好!')
          time.sleep(2)
          print('%s say hello' %name)
      
      if __name__ == '__main__':
          t = Thread(target=sayhi,args=('张三',))
          # 方式1:
          t.setDaemon(True)  # 必须在t.start()之前设置
          # 方式2:
          t.daemon = True
          t.start()
          print('主线程')
      
      

      示例二:守护线程在非守护线程结束前先结束

      from threading import Thread
      import time
      
      def foo():
          print(123)   # 第1步
          time.sleep(1)
          print("end123")  # 第4步
      
      def bar():
          print(456)  # 第2步
          time.sleep(3)
          print("end456")  # 第5步
      
      t1=Thread(target=foo)
      t2=Thread(target=bar)
      
      t1.daemon=True
      t1.start()
      t2.start()
      print("---main---")  # 第3步
      
      # 结果:
      # 123
      # 456
      # ---main---
      # end123
      # end456
      
      

      示例三:守护线程在非守护线程结束之后结束

      from threading import Thread
      import time
      
      def foo():
          print(123)  # 第1步
          time.sleep(3)
          print("end123")
      
      def bar():
          print(456)  # 第2步
          time.sleep(1)
          print("end456")  # 第4步
      
      t1=Thread(target=foo)
      t2=Thread(target=bar)
      
      t1.daemon=True
      t1.start()
      t2.start()
      print("main-------")  # 第3步
      
      # 结果:
      # 123
      # 456
      # main-------
      # end456
      
      

    8. 线程互斥锁

    • 多个任务公抢一个数据,保证数据的安全的目的,要让其串行

    • 代码示例

      from threading import Thread
      from threading import Lock
      import time
      import random
      
      x = 100
      def task(lock):
          lock.acquire()
          global x
          temp = x
          time.sleep(0.01)
          temp = temp - 1
          x = temp
          lock.release()
      
      if __name__ == '__main__':
          mutex = Lock()
          l1 = []
          for i in range(100):
              t = Thread(target=task,args=(mutex,))
              l1.append(t)
              t.start()
      
          for i in l1:
      		i.join()
          print(f'主线程{x}')
      
      
  • 相关阅读:
    Spring自定义注解简单使用四步走
    关于Mybaits映射一点心得
    设置UIButton文字大小颜色不同
    AFNetworking上传文件
    解决UITableView头部空白
    iOS获取文件和文件夹大小
    编译ffmpeg(iOS)
    让MySql支持Emoji表情
    MySQL重置密码(OSX)
    iOS多线程总结
  • 原文地址:https://www.cnblogs.com/liubing8/p/11403483.html
Copyright © 2011-2022 走看看