mkstemp打开太多文件

时间:2019-01-11 16:38:16

标签: python subprocess

我在循环中使用subprocess.run(超过1万次)来调用某些Java命令。 像这样:

 import subprocess
 import tempfile

 for i in range(10000):
     ret = subprocess.run(["ls"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 
     (_, name) = tempfile.mkstemp()
     with open(name, 'w+') as fp:
         fp.write(ret.stdout.decode())

但是,一段时间后,我遇到了以下异常:

Traceback (most recent call last):
  File "mwe.py", line 5, in <module>
    ret = subprocess.run(["ls"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 
  File "/usr/lib/python3.5/subprocess.py", line 693, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/lib/python3.5/subprocess.py", line 947, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.5/subprocess.py", line 1454, in _execute_child
    errpipe_read, errpipe_write = os.pipe()
OSError: [Errno 24] Too many open files

我是否缺少关闭文件描述符的内容? 谢谢

1 个答案:

答案 0 :(得分:2)

mkstemp返回已经打开文件描述符fd,后跟文件名。您将忽略文件描述符(您对名称_的选择表明您已明确选择忽略它),因此,您忽略了关闭它。而是使用文件名第二次打开文件,创建一个文件对象,其中包含同一文件的 second 文件描述符。不管您是否关闭第二个,第一个都保持打开状态。

这是mkstemp方法的解决方案:

 temporaryFiles = []
 for i in range(1000):
     ...
     fd, name = tempfile.mkstemp()
     os.write(fd, ... )
     os.close(fd)
     temporaryFiles.append(name)  # remember the filename for future processing/deletion

在评论中Wyrmwood的建议的基础上,更好的方法是:

 temporaryFiles = []
 for i in range(1000):
     ...
     with tempfile.NamedTemporaryFile(delete=False) as tmp:
         # tmp is a context manager that will automatically close the file when you exit this clause
         tmp.file.write( ... )
         temporaryFiles.append(tmp.name)  # remember the filename for future processing/deletion

请注意,mkstempNamedTemporaryFile构造函数都具有可让您更具体地说明文件位置(dir)和命名(prefix,{{ 1}})。如果要保留文件,则应指定suffix,以便将它们保留在默认的临时目录之外,因为操作系统可能会清除默认位置。