繁体   English   中英

Python中的子进程模块资源暂时不可用错误

[英]Resource temporarily unavailable error with subprocess module in Python

在Python中,我生成了一个gnuplot进程,用于从数据集生成gif图像。

from subprocess import Popen, PIPE
def gnuplotter(...)
    p = Popen([GNUPLOT], shell=False, stdin=PIPE, stdout=PIPE)
    p.stdin.write(r'set terminal gif;')
    ...
    p.stdin.write(contents)
    p.stdout.close()

当我使用gnuplotter()一次时它工作正常,但是当我多次启动进程时,我得到Resource temporarily unavailable错误。

for i in range(54):
    gnuplotter(i, ... 

  File "/Users/smcho/code/PycharmProjects/contextAggregator/aggregation_analyzer/aggregation_analyzer/gnuplotter.py", line 48, in gnuplotter
    p = Popen([GNUPLOT], shell=False, stdin=PIPE, stdout=PIPE)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1205, in _execute_child
    self.pid = os.fork()
OSError: [Errno 35] Resource temporarily unavailable

怎么了,怎么能在喷出另一个之前关闭gnuplot进程呢?

pid数字,打开文件描述符,内存是有限的资源。

fork(2)manual说errno.EAGAIN应该发生时:

[EAGAIN]  The system-imposed limit on the total number of processes under
          execution would be exceeded.  This limit is configuration-dependent.

[EAGAIN]  The system-imposed limit MAXUPRC () on the total number of processes
          under execution by a single user would be exceeded.

要更轻松地重现错误,您可以在程序开头添加:

import resource

resource.setrlimit(resource.RLIMIT_NPROC, (20, 20))

问题可能是所有子进程都处于活动状态,因为您没有调用p.stdin.close()并且当重定向到管道时,gnuplot的stdin可能会被完全缓冲,即gnuplot进程可能会卡在等待输入。 和/或您的应用程序使用太多文件描述符(文件描述符在Python 2.7上默认由子进程继承)而不释放它们。

如果输入不依赖于输出并且输入的大小有限,那么使用.communicate()

from subprocess import Popen, PIPE, STDOUT

p = Popen("gnuplot", stdin=PIPE, stdout=PIPE, stderr=PIPE,
          close_fds=True, # to avoid running out of file descriptors
          bufsize=-1, # fully buffered (use zero (default) if no p.communicate())
          universal_newlines=True) # translate newlines, encode/decode text
out, err = p.communicate("\n".join(['set terminal gif;', contents]))

.communicate()写入所有输入并读取所有输出(并发,因此没有死锁)然后关闭p.stdin,p.stdout,p.stderr(即使输入很小并且gnuplot的端完全缓冲; EOF刷新缓冲区)并等待过程完成(没有僵尸)。

Popen调用_cleanup()在其构造是所有已知的子流程投票退出状态 ,即,即使你不会打电话p.wait()不应该有很多僵尸进程(死了但是未读状态)。

需要调用p.wait()来等待子p.wait()完成,然后在完成与它的通信后收集它。

如果您有特殊情况(您想要启动N并稍后等待它们), p.poll()将让您检查是否已完成。

由于您已设置管道,因此您应该使用p.communicate()来避免死锁。 请参阅文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM