python ---- 多线程

一曲冷凌霜 提交于 2019-11-28 08:38:56

线程,多线程:


  1. 线程的理论知识:

    1. 什么是线程:

      线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位

    2. 进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。

    3. 在内存中开启一个进程空间,然后将主进程的所有的资源数据复制一份,然后去调用线程去执行代码。

    4. 进程是资源单位,线程是执行单位

  2. 线程vs进程:

    1. 启动进程的开销非常大,比开启线程的开销大很多

    2. 开启线程的速度非常快,

    3. 线程与线程之间可以共享数据,进程与进程之间需要借助队列等方法实现通信。

      from threading import Thread
      
      x = 3
      def task():
          global x
          x = 10
      
      if __name__ == '__main__':
          t1 = Thread(target=task)
          t1.start()
          t1.join()
          print(x)
      # x 的值是10,所以在线程中,是可以做到数据共享的
      

      同一进程内的资源数据对于这个进程的多个线程来说是共享的.

  3. 线程的应用:

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

  4. 开启线程的两种方式:

    from threading import Thread   
    # 导入线程的模块
    import time
    import random
    
    def task(name):
        print(f'{name} is running')
        time.sleep(random.random())
        print(f'{name} is gone')
    
    if __name__ == '__main__':
        t = Thread(target=task,args=('周道容',))
        t.start()
        # 开启线程
        print('----主')
    
    from threading import Thread
    import time
    import random
    
    class MyThread(Thread):
    # 定义一个类,继承Thread类,执行其中的一些方法
        def __init__(self,name):
            super().__init__()
            self.name = name
    
        def run(self):    # 必须要有run方法
            print(f'{self.name} is running')
            time.sleep(random.random())
            print(f'{self.name} is gone')
    
    if __name__ == '__main__':
        t = MyThread('周道容')
        t.start()
        print('----主')
    

    其本质是重构Thread类中的run方法

  5. 线程的相关其他方法:

    isAlive() ----- 判断线程是否活着

    getName() ----- 获取线程名

    setName(线程名字) ------ 添加线程名

    name ----- 获取线程名

    threading 方法:

    currentThread() ----- 获取当前线程的对象(需要导入currentThread包)

    import threading
    import time
    
    def run(arg):
        print(f'running sub thread:{threading.currentThread()}')
        threading.currentThread().name = 'task1'
        print(f'sub1 Thread...{threading.currentThread().getName()}')
        print(f'sub2 Thread...{threading.currentThread().name}')
        time.sleep(2)
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=run,args=('t1',))
        t1.start()
        print(f'sub1 Thread...{threading.currentThread().getName()}')
        print(f'sub2 Thread...{threading.currentThread().name}')
    
    '''
    running sub thread:<Thread(Thread-1, started 11788)>
    sub1 Thread...MainThread
    sub1 Thread...task1
    sub2 Thread...MainThread
    sub2 Thread...task1
    '''
    

    enumerate() -------- 返回一个列表,包含所有的线程对象 (需要导入enumerate包)

    activeCount()------ 统计正在运行的线程数

    import threading
    import time
    
    def run(n):
        print(f'task{n}')
        time.sleep(1)
    
    for i in range(3):
        t = threading.Thread(target=run,args=(i,))
        t.start()
    time.sleep(1)
    print(threading.activeCount())
    
  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(time.time()-start_time)
    

    守护线程:

    from threading import Thread
    import time
    
    def task():
        print(123)
        time.sleep(2)
        print(789)
    
    if __name__ == '__main__':
        t = Thread(target=task)
        t.daemon = True
        t.start() 
        print(456)
         # 线程的开启速度非常快,所以会先执行task,输出123,
    # 结果:
    123
    456
    

    注意:

    from threading import Thread
    import time
    
    def foo():
        print(123)
        time.sleep(3)
        print('end123')
    
    def bar():
        print(456)
        time.sleep(3)
        print('end456')
    
    t1=Thread(target=foo)
    t2=Thread(target=foo)
    
    t1.daemon = True
    t1.start()
    t2.start()
    
    print('main-----')
    #结果:
    123
    123
    main-----
    end123
    end123
    
  7. 互斥锁,锁

    由于线程之间都是随机调度的,当它们同时修改一个数据时,就是产生脏数据,所以就会出现锁,使其在同一时间内只能有一个线程对同一个数据进行操作。

    线程锁:

    import threading
    def run():
        global num
        num += 1   
        # 会产生数据不安全
    
    num = 0
    t_obj = []
    for i in range(50):
        t = threading.Thread(target=run)
        t.start()
        t_obj.append(t)
    
    for i in t_obj:
        i.join()
    	# 让其每次执行都按顺序随机
    print(num)
    

互斥锁:

   from threading import Thread
   from threading import Lock
   x = 100
   def task(lock):
       lock.acquire()
       global x
       tem = x
       x = tem - 1
       lock.release()

   if __name__ == '__main__':
       mutex = Lock()
       for i in range(100):
           t = Thread(target=task,args=(mutex,))
           t .start()
       print(x)

with:线程中锁的自动获取和释放等。

所以上边的代码可以写成:

   from threading import Thread,Lock
   
   x = 100
   def task(lock):
       with lock:
           global x
           tem = x
           x = tem - 1
   
   mutex = Lock()
   for i in range(100):
       t = Thread(target=task,args=(mutex,))
       t.start()
   print(x)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!