我想知道为什么子流程会打开这么多文件。我有一个示例,其中某些文件似乎永远保持打开状态(在子进程完成后,甚至在程序崩溃之后)。
请考虑以下代码:
import aiofiles
import tempfile
async def main():
return [await fds_test(i) for i in range(2000)]
async def fds_test(index):
print(f"Writing {index}")
handle, temp_filename = tempfile.mkstemp(suffix='.dat', text=True)
async with aiofiles.open(temp_filename, mode='w') as fp:
await fp.write('stuff')
await fp.write('other stuff')
await fp.write('EOF\n')
print(f"Reading {index}")
bash_cmd = 'cat {}'.format(temp_filename)
process = await asyncio.create_subprocess_exec(*bash_cmd.split(), stdout=asyncio.subprocess.DEVNULL, close_fds=True)
await process.wait()
print(f"Process terminated {index}")
if __name__ == "__main__":
import asyncio
asyncio.run(main())
此顺序依次产生一个进程。我希望与此同时打开的文件数也将是1。事实并非如此,有时我会收到以下错误:
/Users/cglacet/.pyenv/versions/3.8.0/lib/python3.8/subprocess.py in _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)
1410 # Data format: "exception name:hex errno:description"
1411 # Pickle is not used; it is complex and involves memory allocation.
-> 1412 errpipe_read, errpipe_write = os.pipe()
1413 # errpipe_write must not be in the standard io 0, 1, or 2 fd range.
1414 low_fds_to_close = []
OSError: [Errno 24] Too many open files
我尝试运行不带stdout=asyncio.subprocess.DEVNULL
选项的相同代码,但仍然崩溃。 This answer suggested可能是问题出处,错误也指向errpipe_read, errpipe_write = os.pipe()
行。但这似乎不是问题所在(在没有该选项的情况下运行会产生相同的错误)。
如果需要更多信息,这是lsof | grep python
输出的概述:
python3.8 19529 cglacet 7u REG 1,5 138 12918796819 /private/var/folders/sn/_pq5fxn96kj3m135j_b76sb80000gp/T/tmpuxu_o4mf.dat
# ...
# ~ 2000 entries later :
python3.8 19529 cglacet 2002u REG 1,5 848 12918802386 /private/var/folders/sn/_pq5fxn96kj3m135j_b76sb80000gp/T/tmpcaakgz3f.dat
这些是我的子进程正在读取的临时文件。 lsof
的其余输出似乎是合法的东西(打开了库,例如pandas
/numpy
/scipy
/等)。
[现在,我有些疑问:问题可能出自aiofiles
异步上下文管理器吗?也许是不是不关闭文件而不是create_subprocess_exec
的人?
这里有一个类似的问题,但是没有人真正尝试解释/解决问题(仅建议增加限制):Python Subprocess: Too Many Open Files。我真的很想了解发生了什么,我的首要目标不一定是暂时解决问题(将来,我希望能够根据需要多次运行函数fds_test
)。我的目标是拥有一个功能符合预期的功能。我可能必须更改我的期望或代码,这就是为什么我问这个问题。
如注释here中的建议,我还尝试运行python -m test test_subprocess -m test_close_fds -v
,它给出:
== CPython 3.8.0 (default, Nov 28 2019, 20:06:13) [Clang 11.0.0 (clang-1100.0.33.12)]
== macOS-10.14.6-x86_64-i386-64bit little-endian
== cwd: /private/var/folders/sn/_pq5fxn96kj3m135j_b76sb80000gp/T/test_python_52961
== CPU count: 8
== encodings: locale=UTF-8, FS=utf-8
0:00:00 load avg: 5.29 Run tests sequentially
0:00:00 load avg: 5.29 [1/1] test_subprocess
test_close_fds (test.test_subprocess.POSIXProcessTestCase) ... ok
test_close_fds (test.test_subprocess.Win32ProcessTestCase) ... skipped 'Windows specific tests'
----------------------------------------------------------------------
Ran 2 tests in 0.142s
OK (skipped=1)
== Tests result: SUCCESS ==
1 test OK.
Total duration: 224 ms
Tests result: SUCCESS
所以似乎文件应该被正确关闭,我在这里有点丢失。
问题不是来自create_subprocess_exec
,此代码中的问题是tempfile.mkstemp()
实际上打开了文件:
mkstemp()将包含操作系统级别句柄的元组返回到打开的文件(如os.open()将返回的…)
我以为只会创建文件。为了解决我的问题,我仅向tempfile.mkstemp()
添加了一个电话。