Интересно, почему подпроцессы держат так много открытых файлов. У меня есть пример, в котором некоторые файлы остаются открытыми навсегда (после завершения подпроцесса и даже после сбоя программы).
Рассмотрим следующий код:
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())
Это порождает процессы один за другим (последовательно). Я ожидаю, что количество одновременно открытых файлов также будет одним. Но это не так, и в какой-то момент я получаю следующую ошибку:
/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
, но он все равно вылетает. Этот ответ предполагает , возможно, причина возникновения проблемы, и ошибка также указывает на строку 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
выглядят как файлы le git (библиотеки открываются, например, pandas
/ numpy
/ scipy
/ et c.).
Теперь у меня есть некоторые сомнения: может быть, проблема в aiofiles
асинхронном диспетчере контекста? Может это тот, который не закрывает файлы и не create_subprocess_exec
?
Здесь есть похожий вопрос, но никто действительно не пытается объяснить / решить проблему (и только предлагает увеличить ограничение): Python Подпроцесс: слишком много открытых файлов . Мне бы очень хотелось понять, что происходит, моя первая цель - не обязательно временно решить проблему (в будущем я хочу иметь возможность запускать функцию fds_test
столько раз, сколько потребуется). Моя цель - иметь функцию, которая ведет себя так, как ожидалось. Я, вероятно, должен изменить либо мое ожидание, либо мой код, поэтому я задаю этот вопрос.
Как предлагается в комментариях здесь , я также попытался запустить 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
Так что, похоже, файлы должны быть правильно закрыты Я немного потерян здесь.