我在循环中使用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
我是否缺少关闭文件描述符的内容? 谢谢
答案 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
请注意,mkstemp
和NamedTemporaryFile
构造函数都具有可让您更具体地说明文件位置(dir
)和命名(prefix
,{{ 1}})。如果要保留文件,则应指定suffix
,以便将它们保留在默认的临时目录之外,因为操作系统可能会清除默认位置。