美文网首页
Threading多线程

Threading多线程

作者: 冬至是条狗 | 来源:发表于2018-12-13 11:49 被阅读0次

    Python的线程受限制于GIL锁,所以在处理大量运算时不占优势。Cpython解释器的原因。但是日常所用多数属于IO密集型程序,开销要比进程小的多,而且速度快。

    Threading模块中除了常用的Thread类还有一些方法:

    • threading.current_thread()方法:用来表明线程名的方法
    • threading.get_ident() 方法:用来获取线程ID的方法
    • threading.active_count()方法: 用来获取当前活跃的线程数量
    • threading.enumerate() 方法:将线程名字和ID用列表的方式显示出来

    关于守护线程

    • 守护进程会随主进程结束而结束,防止出现僵尸进程。而守护线程则不会随着主线程结束而结束,进程会保留资源留给线程。

    线程锁

    • 同进程锁一样,线程中同样有数据安全问题,为了不让多个线程对一个数据进行操作,使用线程锁可以保证数据安全。

    • 死锁的问题同样存在,使用递归锁RLock()可以解决死锁问题。在多个锁,锁一个数据时,互斥锁Lock()会产生死锁,而RLock()会保证在多个锁有一个在使用时,即使另外一个释放了,其他线程也不会获得锁。

    • 因为线程之间数据共享,所以使用公共数据时应该加锁。

    信号量

    • 同一时间只有N个线程可以访问同一个短代码、数据

      import threading
      import time
      
      def func(sem, a, b):
          sem.acquire()
          time.sleep(1)
          print(a+b)
          sem.release()
      
      sem = threading.Semaphore(4)
      
      for i in range(10):
          t = threading.Thread(target=func, args=(sem, i, i+5))
          t.start()
      

    事件

    • 事件在创建时,自身带有False状态,默认wait()堵塞,clear()设置堵塞,set()清除堵塞。线程的Condition模块中,有acquire()、wait()、release()、notify(int x) 几个方法,wait会等待notify中传入的数字进行执行。wait()在线程函数内部,而notify在外部传入数值,两段代码必须分别用acquire和release包围。

    定时器Timer()

    • 利用定时器可以定时开启一个线程任务。

      def func():
          print("执行定时函数")
      
      
      threading.Timer(5.4, func).start()
      
    • 如果想循环调用一个定是函数,将调用的线程加入到执行函数中即可

      def func():
          print("执行定时函数")
          threading.Timer(5.4, func).start()
      
      threading.Timer(5.4, func).start()
      

    队列 queue

    • 线程中使用的数据都可以共享,当出现数据安全问题时,为了保证线程数据安全,线程中也可以使用队列,这个队列并不在threading模块中,直接导入queue即可:

      import queue
      
      q = queue.Queue()
      q.put()
      q.put_nowait() # 会报错,需要加入异常处理
      q.get()
      q.get_nowait() # 会报错,需要加入异常处理
      
    • queue.LifoQueue() #栈,先进后出

    • queue.PriorityQueue() # 优先级队列

      q = queue.PriorityQueue()
      q.put((20, "a"))
      q.put((10, "b"))
      
      print(q.get())
      # 当优先级一样时,会根据数据的Ascii码排列先出顺序
      

    线程池

    使用python中新模块,concurrent中的线程池,同样也有进程池

    import time
    from concurrent.futures import ThreadPoolExecutor
    
    
    def func(n):
        time.sleep(2)
        print(n)
    
    
    tpool = ThreadPoolExecutor(max_workers=5)
    for i in range(20):
        tpool.submit(func, i)
    
    • shutdown() 可以实现 join 和 close 效果

    • result() 可以取得返回的结果

      import time
      from concurrent.futures import ThreadPoolExecutor
      
      
      def func(n):
          time.sleep(2)
          print(n)
          return n*n
      
      
      tpool = ThreadPoolExecutor(max_workers=5)
      t_list = []
      for i in range(20):
          t = tpool.submit(func, i)  # 取结果
          t_list.append(t)
      tpool.shutdown()  # 等待所有线程执行完,并回收资源后继续执行主线程
      print("主进程")
      
      for t in t_list:
          print(t.result())  # 打印结果,使用result()取出结果
      
    • 在取得结果时,可以不用等待全部线程执行完,利用主线程取得结果即可。

    回调函数

    • 当线程有返回值时,可以利用回调函数进行再次处理:
      import time
      from concurrent.futures import ThreadPoolExecutor
      def func(n):
          time.sleep(2)
          print(n)
          return n*n
    
    
      def call_back(n):
          print("执行的结果是:", n.result())  # 这里传入的时一个对象,需要进行result
    
    
      tpool = ThreadPoolExecutor(max_workers=5)
    
      for i in range(20):
          tpool.submit(func, i).add_done_callback(call_back)
    
      # tpool.shutdown()  # 等待所有线程执行完,并回收资源后继续执行主线程
      print("主进程")
    

    相关文章

      网友评论

          本文标题:Threading多线程

          本文链接:https://www.haomeiwen.com/subject/suaphqtx.html