Ограничить количество подпроцессов. Открыть - PullRequest
2 голосов
/ 18 февраля 2020

Исходя из запуска нескольких экземпляров сценария python одновременно Теперь я могу написать программу python для запуска нескольких экземпляров.

import sys
import subprocess

for i in range(1000):
  subprocess.Popen([sys.executable, 'task.py', '{}in.csv'.format(i), '{}out.csv'.format(i)])

Это запускает 1000 подпроцессов одновременно. Если команда, выполняемая каждым подпроцессом, требует значительных вычислительных ресурсов, это может привести к загрузке компьютера (может даже к sh).

Есть ли способ, которым я могу ограничить число подпроцессов бежать за раз? Например, что-то вроде этого:

if (#subprocess_currently_running = 10) {
   wait(); // Or sleep 
}

Это просто позволяет 10 подпроцессам запускаться одновременно. В случае, если один из десяти завершает, начинайте новый.

1 Ответ

1 голос
/ 18 февраля 2020

Подсчет семафора - это старый добрый механизм, который может использоваться для контроля / управления максимальным количеством одновременно работающих потоков / процессов.

Но как каждый subprocess.Popen объект (подразумевающий процесс) должен ждать завершения, официальный do c сообщает нам о важном недостатке subprocess.Popen.wait() (для этого случая нескольких параллельных подпроцессов):

Примечание: Функция реализована с использованием занятого l oop (неблокирующий вызов и короткие сны). Используйте модуль asyncio для асинхронного ожидания: см. asyncio.create_subprocess_exec.

Таким образом, для нас предпочтительно переключиться на:


Как это можно реализовать:

import asyncio
import sys

MAX_PROCESSES = 10


async def process_csv(i, sem):
    async with sem:  # controls/allows running 10 concurrent subprocesses at a time
        proc = await asyncio.create_subprocess_exec(sys.executable, 'task.py',
                                                    f'{i}in.csv', f'{i}out.csv')
        await proc.wait()


async def main():
    sem = asyncio.Semaphore(MAX_PROCESSES)
    await asyncio.gather(*[process_csv(i, sem) for i in range(1000)])


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