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 语言里实现多线程

  • 相关阅读:
    JavaScript实现Map、Reduce和Filter
    Javascript常用对象的属性和方法
    自己封装的Ajax
    JavaScript函数调用规则
    JavaScript模板引擎使用
    java 简单贪吃蛇
    java邮件发送(含附件)
    java 读写Oracle Blob字段
    java 连接飞信API
    非常棒的Java REST服务器栈
  • 原文地址:https://www.cnblogs.com/ExMan/p/13631694.html
Copyright © 2011-2022 走看看