Добавьте слой многопоточности в Asyncio

#python #python-3.x #multithreading #python-asyncio

Вопрос:

В настоящее время у меня есть этот фрагмент кода, который отлично работает с помощью AsyncIO.

 async def main():

    while(1):
        loop.create_task(startAsyncJob())
        await asyncio.sleep(1)


async def startAsyncJob():
    #myCodeHere


loop = asyncio.get_event_loop()
loop.run_until_complete(main())
 

Я попытался добавить многопоточный слой, чтобы я мог одновременно запускать несколько фрагментов того, что находится внутри моего «основного». Поэтому я извлек его код, поместил его в собственную функцию AsyncJobThread , которую запускаю через свою новую основную функцию с помощью потоков:

 def main():

    try:
        _thread.start_new_thread( AsyncJobThread, (1))
        _thread.start_new_thread( AsyncJobThread, (15))
    except:
        print ("Error: unable to start thread")

async def AsyncJobThread(frequence):
    while(1):
        loop.create_task(startAsyncJob())
        await asyncio.sleep(frequence)


async def startAsyncJob():
    #myCodeHere

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
 

Однако текущая реализация выдает мне следующую ошибку:

 sys:1: RuntimeWarning: coroutine 'AsyncJobThread' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
 

Комментарии:

1. Вы не можете так смешивать потоки и асинхронность. Вам нужно будет запустить новый цикл событий внутри каждого потока. Почему бы вместо этого не использовать что-то вроде asyncio.gather запуска нескольких задач одновременно?

2. Никогда не использовал ничего подобного, на самом деле я только вчера начал использовать asyncio. Не могли бы вы подробно рассказать, как бы вы это asyncio.gather сделали, в ответе, пожалуйста?

3. @dirn Спасибо, я только что попробовал использовать новый цикл событий для каждого потока, и это сработало.

4. Кстати, нет причин использовать _thread вместо threading.Thread этого . (или, возможно, есть, но вам действительно нужно знать, что вы делаете). Как правило, если что-то начинается с _ Python, вы не должны использовать это напрямую (это эквивалент «частных» переменных в других языках).

Ответ №1:

Как и было запрошено, вот ваш код, измененный для использования asyncio.gather .

 async def main():
    await asyncio.gather(
        AsyncJobThread(1),
        AsyncJobThread(15),
    )

async def AsyncJobThread(frequence):
    loop = asyncio.get_event_loop()
    while True:
        loop.create_task(startAsyncJob())
        await asyncio.sleep(frequence)


async def startAsyncJob():
    #myCodeHere

asyncio.run(main())
 

Вы также можете получить ссылку на цикл и передать ее, AsyncJobThread если хотите.