【问题标题】:OS starts killing processes when multi-threaded python process runs当多线程python进程运行时,操作系统开始杀死进程
【发布时间】:2012-03-26 23:41:17
【问题描述】:

这是最奇怪的事情!

我有一个用 Python 编写的多线程客户端应用程序。我正在使用线程同时下载和处理页面。我会使用 cURL 多句柄,除了瓶颈肯定是此应用程序中的处理器(而不是带宽),因此使用线程池更有效。

我有一个 64b i7 摇摆 16GB RAM。仡。我在听 Pandora 并拖钓 Stackoverflow 和 BAM 的同时启动了 80 个线程!父进程有时会以消息结束

Killed

其他时候,单个页面(这是 Chrome 中的自己的进程)会死掉。其他时候整个浏览器崩溃。

如果你想看一点代码,这里是它的要点:

这是父进程:

def start( ):
  while True:
    for url in to_download:
      queue.put( ( url, uri_id ) )

    to_download = [ ]

    if queue.qsize( ) < BATCH_SIZE:
      to_download = get_more_urls( BATCH_SIZE )

    if threading.activeCount( ) < NUM_THREADS:
      for thread in threads:
        if not thread.isAlive( ):
          print "Respawning..."
          thread.join( )
          threads.remove( thread )
          t = ClientThread( queue )
          t.start( )
          threads.append( t )

    time.sleep( 0.5 )

这是 ClientThread 的要点:

class ClientThread( threading.Thread ):

  def __init__( self, queue ):
    threading.Thread.__init__( self )
    self.queue = queue

  def run( self ):
    while True:
      try:
        self.url, self.url_id = self.queue.get( )
      except:
        raise SystemExit

      html = StringIO.StringIO( )
      curl = pycurl.Curl( )
      curl.setopt( pycurl.URL, self.url )
      curl.setopt( pycurl.NOSIGNAL, True )
      curl.setopt( pycurl.WRITEFUNCTION, html.write )
      curl.close( )

      try:
        curl.perform( )
      except pycurl.error, error:
        errno, errstr = error
        print errstr

      curl.close( )

编辑:哦,对了......忘了问这个问题......应该很明显:为什么我的进程会被杀死?它发生在操作系统级别吗?内核级别?这是由于我可以拥有的打开 TCP 连接数的限制吗?我一次可以运行的线程数是否有限制? cat /proc/sys/kernel/threads-max 的输出是 257841。所以……我不认为是这样……

我想我明白了...好吧...我的驱动器上根本没有交换空间。现在有没有办法创建一些交换空间?我正在运行 Fedora 16。有交换...然后我启用了所有 RAM,它神奇地消失了。拖尾/var/log/messages我发现了这个错误:

Mar 26 19:54:03 gazelle kernel: [700140.851877] [15961]   500 15961    12455     7292   1       0             0 postgres
Mar 26 19:54:03 gazelle kernel: [700140.851880] Out of memory: Kill process 15258 (chrome) score 5 or sacrifice child
Mar 26 19:54:03 gazelle kernel: [700140.851883] Killed process 15258 (chrome) total-vm:214744kB, anon-rss:70660kB, file-rss:18956kB
Mar 26 19:54:05 gazelle dbus: [system] Activating service name='org.fedoraproject.Setroubleshootd' (using servicehelper)

【问题讨论】:

  • 检查dmesg(8) 输出以查看内核是否记录了任何信息。
  • dmesg(8) 中的最后一个条目与我的 wifi 适配器与我的路由器相关联。 ...几小时前

标签: python kill pycurl python-multithreading


【解决方案1】:

您已触发内核的内存不足 (OOM) 处理程序;它以一种复杂的方式选择要杀死的进程,尝试尽可能少地杀死进程以产生最大的影响。根据内核使用的标准,Chrome 显然是最容易杀死的进程。

您可以在 /proc/[pid]/oom_score 文件下的 proc(5) 联机帮助页中查看条件摘要:

   /proc/[pid]/oom_score (since Linux 2.6.11)
          This file displays the current score that the kernel
          gives to this process for the purpose of selecting a
          process for the OOM-killer.  A higher score means that
          the process is more likely to be selected by the OOM-
          killer.  The basis for this score is the amount of
          memory used by the process, with increases (+) or
          decreases (-) for factors including:

          * whether the process creates a lot of children using
            fork(2) (+);

          * whether the process has been running a long time, or
            has used a lot of CPU time (-);

          * whether the process has a low nice value (i.e., > 0)
            (+);

          * whether the process is privileged (-); and

          * whether the process is making direct hardware access
            (-).

          The oom_score also reflects the bit-shift adjustment
          specified by the oom_adj setting for the process.

如果你想让 Python 程序被杀死,你可以为你的 Python 程序调整 oom_score 文件。

可能更好的方法是向您的系统添加更多交换,以尝试推迟调用 OOM-killer 的时间。诚然,拥有更多交换并不一定意味着您的系统永远不会耗尽内存——如果有大量交换流量,你可能不会关心它的处理方式——但它至少可以让你度过难关内存问题。

如果您已经为交换分区分配了所有可用空间,则可以添加交换文件。因为它们通过文件系统,所以交换文件比交换分区的开销更大,但您可以在驱动器分区后添加它们,使其成为一个简单的短期解决方案。您使用dd(1) 命令分配文件(不要使用seek 制作稀疏文件)然后使用mkswap(8) 格式化文件以供交换使用,然后使用swapon(8)打开该特定文件。 (我认为您甚至可以将交换文件添加到 fstab(5) 以使其在下次重新启动时自动可用,但我从未尝试过并且不知道语法。)

【讨论】:

    【解决方案2】:

    你正在做一个

    raise SystemExit
    

    它实际上退出了 Python 解释器,而不是你正在运行的线程。

    【讨论】:

    • 这很好,它不能解释为什么一个完全独立的进程会死掉。请参阅上面的编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    • 2018-10-14
    相关资源
    最近更新 更多