65

我正在使用 subprocess 调用另一个程序并将其返回值保存到变量中。这个过程在循环中重复,几千次后程序崩溃并出现以下错误:

Traceback (most recent call last):
  File "./extract_pcgls.py", line 96, in <module>
    SelfE.append( CalSelfEnergy(i) )
  File "./extract_pcgls.py", line 59, in CalSelfEnergy
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
  File "/usr/lib/python3.2/subprocess.py", line 745, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.2/subprocess.py", line 1166, in _execute_child
    errpipe_read, errpipe_write = _create_pipe()
OSError: [Errno 24] Too many open files

任何想法如何解决这个问题都非常感谢!

注释提供的代码:

cmd = "enerCHARMM.pl -parram=x,xtop=topology_modified.rtf,xpar=lipid27_modified.par,nobuildall -out vdwaals {0}".format(cmtup[1])
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
out, err = p.communicate()
4

9 回答 9

56

在 Mac OSX (El Capitan) 中查看当前配置:

#ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 256
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited

打开文件值设置为 10K :

#ulimit -Sn 10000

验证结果:

#ulimit -a

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 10000
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited
于 2016-02-06T02:42:32.613 回答
24

我猜这个问题是由于我正在使用子进程处理一个打开的文件:

cmd = "enerCHARMM.pl -par param=x,xtop=topology_modified.rtf,xpar=lipid27_modified.par,nobuildall -out vdwaals {0}".format(cmtup[1])
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

这里的 cmd 变量包含一个刚刚创建但尚未关闭的文件的名称。然后subprocess.Popen在该文件上调用系统命令。多次执行此操作后,程序因该错误消息而崩溃。

所以我从中学到的信息是

关闭您创建的文件,然后处理它

于 2013-05-13T19:04:46.517 回答
15

You can try raising the open file limit of the OS:

ulimit -n 2048

于 2013-05-13T17:27:55.857 回答
9

正如其他人所指出的,提高 /etc/security/limits.conf 中的限制以及文件描述符对我个人来说是一个问题,所以我做到了

sudo sysctl -w fs.file-max=100000 

并添加到 /etc/sysctl.conf:

fs.file-max = 100000

重新加载:

sudo sysctl -p

此外,如果您想确保您的过程不受其他任何东西(我的)的影响,请使用

cat /proc/{process id}/limits 

找出你的进程的实际限制是什么,对我来说,运行 python 脚本的软件也应用了它的限制,这些限制已经覆盖了系统范围的设置。

在解决了我的这个错误的特定问题后,在这里发布这个答案,希望它对某人有所帮助。

于 2016-10-26T19:32:16.433 回答
6

创建的子进程Popen()可以从父进程继承打开的文件描述符(有限资源)。在 POSIX 上使用close_fds=True(自 Python 3.2 起默认),以避免它。此外,“PEP 0446 - 使新创建的文件描述符不可继承”处理了一些遗留问题(自 Python 3.4 起)

于 2016-02-13T13:20:36.927 回答
4

也许您正在多次调用该命令。如果是这样,每次你在做stdout=subprocess.PIPE. 在每次通话之间尝试做p.stdout.close()

于 2018-08-23T15:09:20.857 回答
3

改用上下文管理器:

cmd = "enerCHARMM.pl -param=x,xtop=topology_modified.rtf,xpar=lipid27_modified.par,nobuildall -out vdwaals {0}".format(cmtup[1])
with subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) as p:
    out, err = p.communicate()

这将在最后一行之后p.stdout关闭。p.stderr

Python中的相关代码:https ://github.com/python/cpython/blob/208a7e957b812ad3b3733791845447677a704f3e/Lib/subprocess.py#L1031-L1038

相关文档:https ://docs.python.org/3/library/subprocess.html#subprocess.Popen

于 2021-08-01T02:31:56.240 回答
0

如果您在 Linux 上工作,您可以轻松调试此问题

1 - 启动由于终端中打开的文件过多而最终失败的命令。

python -m module.script

2 - 让它运行一段时间(这样它就可以开始打开实际文件),只要你相信它已经这样做了,只需按一下CTRL+Z,这个过程就会暂停。您将获得带有进程 ID 的输出。

^Z
[2]  + 35245 suspended  python -m module.script

35245是你的PID。

3 - 现在您可以检查实际打开和未关闭的文件。

ls -alht /proc/35245/fd/

就我而言,我正在做一些与原始帖子非常相似的事情,但我tempfile.mkstemp()在添加一些数据并实际运行subprocess.Popen.

在这种情况下,您需要关闭文件两次,一次用于添加信息,第二次用于添加信息mkstemp

fd, path = tempfile.mkstemp()
with open(path, "wb") as f:
    f.write(bytes('my data', encoding='utf8'))
    f.close()   # this is one time
process = subprocess.Popen("my command that requires the previous file" ,[...])
os.close(fd)   # this is second time and the one I missed
于 2021-07-22T01:57:35.637 回答
-2

在子进程中打开文件。它正在阻止呼叫。

ss=subprocess.Popen(tempFileName,shell=True)
 ss.communicate()
于 2013-10-10T13:22:57.303 回答