簡體   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