Python之并发编程(五)多线程

并发编程之多线程

  1. 多线程的概念介绍

    threading模块介绍:threading模块和multiprocessing模式在使用层面,有甚大的相似性

  2. 开启多线程的两种方式

    1. 开启进程的第一种方式:

      #1.创建线程的开销比创建进程的开销小,因而创建线程的速度快
      from multiprocessing import Process
      from threading import Thread
      import os
      import time
      def work():
          print('<%s> is running'%os.getpid())
          time.sleep(2)
          print('<%s> is done'%os.getpid())
      
      if __name__ == '__main__':
          t=Thread(target=work,)
          # t= Process(target=work,)
          t.start()
          print('主',os.getpid())
      
      #开启进程的第一种方式
    2. 开启进程的第二种方式(用类):

      from threading import Thread
      import time
      class Work(Thread):
          def __init__(self,name):
              super().__init__()
              self.name = name
          def run(self):
              # time.sleep(2)
              print('%s say hell'%self.name)
      if __name__ == '__main__':
          t = Work('egon')
          t.start()
          print('主')
      
      #开启线程的第二种方式(用类)
  3. 在一个进程开启多个线程与在一个进程下开始多个子进程的区别:

    1. 线程的开启速度大于进程的开启速度

      from  multiprocessing import Process
      from threading import Thread
      import time
      def work():
          time.sleep(2)
          print('hello')
      if __name__ == '__main__':
          t = Thread(target=work)#如果等上几秒,他会在开启的过程中先打印主,如果不等会先打印hello
          # t = Process(target=work) #子进程会先打印主,
          t.start()
          print('主')
      
      
      #线程的开启速度大于进程的开启速度
    2. 在同一个进程下开多个进程和开多个线程的pid不同

      # 2.----------
      from  multiprocessing import Process
      from threading import Thread
      import os
      def work():
          print('hello',os.getpid())
      if __name__ == '__main__':
          #在主进程下开启多个线程,每个线程都跟主进程的pid一样
          t1= Thread(target=work)
          t2 = Thread(target=work)
          t1.start()
          t2.start()
          print('主线程pid',os.getpid())
      
          #来多个进程,每个进程都有不同的pid
          p1 = Process(target=work)
          p2 = Process(target=work)
          p1.start()
          p2.start()
          print('主进程pid', os.getpid())
      
      #在同一个进程下开多个进程和开多个线程的pid的不同
    3. 同一进程内的线程共享该进程的数据

      from  threading import Thread
      from multiprocessing import  Process
      import os
      def work():
          global n
          n-=1
          print(n)  #所以被改成99了
      n = 100
      if __name__ == '__main__':
          # p = Process(target=work)
          p = Thread(target=work)  #当开启的是线程的时候,因为同一进程内的线程之间共享进程内的数据
                                  #所以打印的n为99
          p.start()
          p.join()
          print('主',n) #毫无疑问子进程p已经将自己的全局的n改成了0,
          # 但改的仅仅是它自己的,查看父进程的n仍然为100
      
      #同一进程内的线程共享该进程的数据

      线程和进程的区别:

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

    from threading import Thread
    from threading import currentThread
    from threading import  enumerate
    from threading import activeCount
    import time
    import os
    def task():
        time.sleep(2)
        print('666')
    if __name__ == '__main__':
        t1 = Thread(target=task,name='线程1')
        t2 = Thread(target=task,name='线程2')
        t1.start()
        t2.start()
    
        print(t1.isAlive())   # 判断线程是否还在活动 返回布尔值
        print(t1.getName())   # 获取线程名称
        t1.setName('gou')     # 设置线程名称
        print(t1.name)      
        print(currentThread())   # 获取当前线程
        print(enumerate())   # 获取当前进程下所有线程,并以列表形式返回
        print(activeCount())   # 获取还在活动的线程数
        print(f"==主线程{os.getpid()}")
    # 结果:
    True
    线程1
    gou
    <_MainThread(MainThread, started 11472)>
    [<_MainThread(MainThread, started 11472)>, <Thread(gou, started 1876)>, <Thread(线程2, started 8760)>]
    3
    ==主线程12980
    666
    666
  5. 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=('海狗1',))
          t3 = Thread(target=task,args=('海狗2',))
      
          t1.start()
          t1.join()   
          t2.start()
          t2.join()
          t3.start()
          t3.join()
      
          print(f'===主线程{time.time() - start_time}')  # 线程是没有主次之分的.
      # 结果:
      海狗 is running
      海狗 is gone
      海狗1 is running
      海狗1 is gone
      海狗2 is running
      海狗2 is gone
      ===主线程3.0049641132354736
    • 守护线程:守护线程 等待非守护子线程以及主线程结束之后,结束.

      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=('egon',))
          # t.setDaemon(True) #必须在t.start()之前设置
          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
    • 面试题

      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
  6. 互斥锁

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

      from threading import Thread
      import time
      import random
      x = 100
      
      def task():
          global x
          temp = x
          time.sleep(random.randint(1, 3))
          temp = temp - 1
          x = temp
      
      
      if __name__ == '__main__':
          l1 = []
          for i in range(100):
              t = Thread(target=task)
              l1.append(t)
              t.start()
      
          for i in l1:
              i.join()
          print(f'主线程{x}')
      # 结果:  # 相当于对全局变量赋值100次99
      主线程99
      from threading import Thread
      from threading import Lock
      import time
      import random
      x = 100
      
      def task(lock):
      
          lock.acquire()
          # time.sleep(random.randint(1,2))
          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()
      
          time.sleep(3)
          print(f'主线程{x}')
      # 结果:
      主线程0

猜你喜欢

转载自www.cnblogs.com/zhangdadayou/p/11431941.html