Выполнение внешней команды в рабочем процессе и захват вывода в один файл - PullRequest
2 голосов
/ 19 июня 2019

Это мой наивный подход для вызова внешних команд в рабочем процессе и добавления всех выходных данных команд в один файл.Это пример кода.

from concurrent.futures import ProcessPoolExecutor
from functools import partial
import multiprocessing
import subprocess

def worker_process_write_output(fh, lock, mylist):
    output = subprocess.run("dir /b", shell=True, stdout=subprocess.PIPE, universal_newlines=True).stdout
    with lock:  # Need lock to prevent multiple processes writing to the file simultenously
        fh.write(mylist)
        fh.writelines(output)    

if __name__ == '__main__':
    with open("outfile.txt", "a") as fh: # I am opening file in main process to avoid the overhead of opening & closing the file multiple times in each worker process
        mylist = [1, 2, 3, 4]
        with ProcessPoolExecutor() as executor:
            lock = multiprocessing.Manager().Lock()
            executor.map(partial(worker_process_write_output, fh, lock), mylist)

Этот код зависает при запуске.Какие есть ошибки и исправления?Некоторые из них, я думаю, 1. Не могу передать дескриптор файла рабочему процессу.Нужно открыть и закрыть файл в рабочем процессе.Не уверен в причине 2. Не могу использовать subprocess.run в рабочем процессе, нужно использовать os.popen ("dir / b"). Read () или что-то еще 3. Не уверен, нужна ли блокировка и если это необходимоэто правильный замок?

1 Ответ

1 голос
/ 19 июня 2019

Контексты файлов могут быть переданы между процессами , поэтому я не уверен, почему ваш код блокируется в обработчике файлов. Сказав это, я предполагаю, что вы выполняете большую работу в своей функции run(), поэтому накладные расходы по открытию / закрытию файла один раз за процесс не должны быть ужасно значительными. Если проделана небольшая работа, многопроцессорная обработка, возможно, в любом случае не лучший выбор, поскольку она требует серьезных накладных расходов.

Кроме того, fh.write(mylist) повышает TypeError: write() argument must be str, not int, поэтому нам нужно разыграть с fh.write(str(mylist)).

Вот обходной путь:

import multiprocessing
import subprocess
from concurrent.futures import ProcessPoolExecutor
from functools import partial

def worker_process_write_output(lock, mylist):
    output = subprocess.run("dir /b", shell=True, stdout=subprocess.PIPE,
                            universal_newlines=True).stdout

    with lock:
        with open("outfile.txt", "a") as fh:
            fh.write(str(mylist))
            fh.writelines(output)


if __name__ == '__main__':
    mylist = [1, 2, 3, 4]

    with ProcessPoolExecutor() as executor:
        lock = multiprocessing.Manager().Lock()
        executor.map(partial(worker_process_write_output, lock), mylist)
...