mkstemp открывает слишком много файлов - PullRequest
0 голосов
/ 11 января 2019

Я использую subprocess.run в цикле (более 10 000 раз) для вызова какой-либо команды 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 голосов
/ 11 января 2019

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

Основываясь на предложении Уирмвуда в комментариях, еще лучший подход будет:

 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, suffix). Если вы хотите сохранить файлы, вы должны указать dir, чтобы они не попадали во временный каталог по умолчанию, так как расположение по умолчанию может быть очищено ОС.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...