python проблема с потоками

Всем привет, есть файл .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, и к тому же через время и они останавливаются.


Ответы (1 шт):

Автор решения: insolor

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

import asyncio

i = 0


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

        cmd = f"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(), но через asyncio получается более просто, на мой взгляд.

→ Ссылка