zoukankan      html  css  js  c++  java
  • 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
        
  • 相关阅读:
    MySQL的安装和基本管理
    前端基础之jQuery
    前端基础之BOM和DOM
    前端基础之JavaScript
    前端基础之CSS
    前端基础之HTML
    五,pod控制器应用进阶
    运维都该会的Socket知识!
    四,k8s集群资源清单定义入门
    三,k8s集群的应用入门
  • 原文地址:https://www.cnblogs.com/zhangdadayou/p/11431941.html
Copyright © 2011-2022 走看看