Запуск exe файла много раз параллельно

Рейтинг: 1Ответов: 1Опубликовано: 02.02.2023

Всем привет, есть файл .exe который выполняется +- 10 секунд, запускать этот файл обычным циклом очень долго, так как запустить его нужно много раз. Я решил использовать потоки для этого:

import subprocess
import threading

mutex = threading.Lock()

i = 0

def worker():
    global i
    
    while True:
        mutex.acquire()
        i += 1
        mutex.release() 

        cmd = f"C:\\Users\\123\\Desktop\\main.exe"
        
        
        returned_output = str(subprocess.check_output(cmd))
        print(returned_output)
                


def run_workers(count):
    threads = [threading.Thread(target=worker) for i in range(0, count)]

    for thread in threads:
        thread.start()  # каждый поток должен быть запущен

    for thread in threads:
        print("Поток завершился")
        thread.join()  # дожидаемся исполнения всех потоков


if __name__ == "__main__":
    run_workers(50)

main.exe не сильно нагружает компьютер, по этому 50 потоков нагрузит на 20% компьютер. Проблема в том что, когда запускаешь, он все равно медленно работает, а в диспетчере задач показано что запущено 3-4 main.exe. В чем проблема? почему вместо 50 запускается 3-4 main.exe, и к тому же через время и они останавливаются.

Ответы

▲ 3Принят

Попробуйте через asyncio вместо threading:

import asyncio

i = 0


async def worker():
    global i
    
    while True:
        i += 1

        cmd = "C:\\Users\\123\\Desktop\\main.exe"
        proc = await asyncio.create_subprocess_shell(
            cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )

        stdout, stderr = await proc.communicate()

        print(f'[{cmd!r} exited with {proc.returncode}]')
        if stdout:
            print(f'[stdout]\n{stdout.decode()}')
        if stderr:
            print(f'[stderr]\n{stderr.decode()}')


async def run_workers(count):
    workers = [worker() for i in range(0, count)]
    await asyncio.gather(*workers)


if __name__ == "__main__":
    asyncio.run(run_workers(50))

На основе документации: https://docs.python.org/3/library/asyncio-subprocess.html


Вариант реализации в одном потоке и без асинхронности, просто в бесконечном цикле проверяем состояние процессов через Popen.poll(), поддерживаем количество живых процессов равным count:

import subprocess
import time

cmd = "C:\\Users\\123\\Desktop\\main.exe"


def run_workers(count):
    processes = []
    
    while True:
        alive_processes = []
        
        # Вывод результата завершенных процессов, оставляем в списке только живые процессы
        for proc in processes:
            if proc.poll() is None:
                alive_processes.append(proc)
            else:
                stdout, stderr = proc.communicate(input=None, timeout=None)
                
                print(f'[{cmd!r} exited with {proc.returncode}]')
                
                if stdout:
                    print(f'[stdout]\n{stdout.decode()}')
                if stderr:
                    print(f'[stderr]\n{stderr.decode()}')
        
        processes = alive_processes
        
        # Если живых процессов меньше count, запускаем дополнительные
        for _ in range(len(alive_processes), count):
            processes.append(subprocess.Popen([cmd]))
        
        time.sleep(0.1)


if __name__ == "__main__":
    run_workers(50)