zoukankan      html  css  js  c++  java
  • python多进程假死

    结论:python多进程间用Queue通信时,如果子进程操作Queue满了或者内容比较大的情况下,该子进程会阻塞等待取走Queue内容(如果Queue数据量比较少,不会等待),如果调用join,主进程将处于等待,等待子进程结束,造成死锁

    解决方式:在调用join前,及时把Queue的数据取出,而且Queue.get需要在join前

    原理分析

    模拟子进程阻塞:

    1.  
      from multiprocessing import Process, Queue
    2.  
       
    3.  
       
    4.  
      def fun(q):
    5.  
      num = 1000000000
    6.  
      q.put('=' * num)
    7.  
      print("done put")
    8.  
       
    9.  
       
    10.  
      if __name__ == '__main__':
    11.  
      queue = Queue()
    12.  
      p = Process(target=fun, args=(queue,))
    13.  
      p.start()
    14.  
      p.join()
    15.  
      print("done")

    原因分析:

    1.  
      #
    2.  
      # Queue type using a pipe, buffer and thread
    3.  
      #
    4.  
       
    5.  
      class Queue(object):

    multiprocessing.Queue底层是基于Pipe构建,操作系统管道不是无限长,因此子进程在执行put()期间,处于阻塞,直到某些其他进程使用get()从队列中取走数据。上例中,主进程等待子进程,打印不了done

    而当队列put数据比较少时,是没有问题的,先打印done put,再打印done,但这样写法是有隐患,当put数据比较多时,就会阻塞

    1.  
      from multiprocessing import Process, Queue
    2.  
       
    3.  
       
    4.  
      def fun(q):
    5.  
      num = 1
    6.  
      q.put('=' * num)
    7.  
      print("done put")
    8.  
       
    9.  
       
    10.  
      if __name__ == '__main__':
    11.  
      queue = Queue()
    12.  
      p = Process(target=fun, args=(queue,))
    13.  
      p.start()
    14.  
      p.join()
    15.  
      print("done")

    正确的写法

    1.  
      from multiprocessing import Process, Queue
    2.  
       
    3.  
       
    4.  
      def fun(q):
    5.  
      num = 1000000000
    6.  
      q.put('=' * num)
    7.  
      print("done put")
    8.  
       
    9.  
       
    10.  
      if __name__ == '__main__':
    11.  
      queue = Queue()
    12.  
      p = Process(target=fun, args=(queue,))
    13.  
      p.start()
    14.  
      queue.get()
    15.  
      p.join()
    16.  
      print("done")

    在join前面调用queue.get

    注意!!!以下这样写法也是不对的,join要在queue.get前面,不然主进程等待子进程结束,而子进程等待队列数据取走,造成死锁

    1.  
      p = Process(target=fun, args=(queue,))
    2.  
      p.start()
    3.  
      p.join()
    4.  
      queue.get()

    Python多线程补充

    Python 是一门解释型语言,它的执行是由解释器来控制的。

    GIL,全称是 Global Interpreter Lock ,全局解释锁 ,专门给解释器用

    一般情况下在用户态下是无法做到线程级别的时间片轮转

    但是 python 能做到!python 里,解释器可以记录每一个线程执行了多长时间——时间一到,就能够切换到另一条线程。

    GIL 就是拿来给线程加锁的,当一个线程将要执行时,解释器会把 GIL 锁给这个线程,其他线程因为没有锁,是无法运行的。等到持有锁线程阻塞或者运行 100 个字节码,解释器就会把锁交给其他线程。

    但是这个 GIL 锁是全局(Global)的,也就导致即使是多核情况下,一次也只有一个线程能运行,从整体上看,整个程序是串行的。

    python多线程应用

    拿爬虫程序来说吧,单个爬虫总会花时间在下载网页上,很多 CPU 时间就浪费掉了,提供 sleep 机制后,这些爬虫可以在等待下载时释放 GIL 锁,把机会让给其他爬虫,这样整体运行速度能够得到大幅提升

    也就是说 Python 的多线程适合 I/O 密集型的程序,但是对计算密集型程序就不那么友好了

    对于计算密集型程序用多进程或者让 python 调用 C 语言的代码,在 C 语言里实现多线程

  • 相关阅读:
    (引)spring学习笔记1.什么是控制反转
    Arduino 各种模块篇 步进电机 step motor 舵机 servo 直流电机 总复习
    Raspberry Pi Wireless Adaptor
    Pyramid 使用总结1
    Arduino 各种模块篇 人体红外感应模块 proximity sensor
    Pyramid 使用总结2
    Webcam Streaming Desktop Recording on Linux for ubuntu or its destros
    Arduino 各种模块篇 步进电机 step motor( 不用库,不用shield, 纯)
    Arduino 各种模块篇 motor shield 电机扩展板(舵机、直流电机、步进电机party)
    转载 stepper motors
  • 原文地址:https://www.cnblogs.com/ExMan/p/13631694.html
Copyright © 2011-2022 走看看