Проблемы с использованием asyncio в потоке

#python #multithreading #python-asyncio

Вопрос:

Нет никаких проблем с использованием asyncio следующим образом.

 import asyncio


async def main():
    await asyncio.sleep(1)
    aaa = 1
    print (aaa)


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

Однако я должен использовать asyncio в потоке, как показано в простом коде ниже, что приводит к следующей ошибке

 import asyncio
import threading

async def main():
    await asyncio.sleep(1)
    aaa = 1
    print (aaa)


def test():
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()


t=threading.Thread(target=test)
t.start()
 

Сообщение об ошибке (Ошибка выполнения: В потоке «Поток-1» отсутствует текущий цикл событий.)

 Exception in thread Thread-1:
Traceback (most recent call last):
  File "D:Anaconda3Libthreading.py", line 932, in _bootstrap_inner
    self.run()
  File "D:Anaconda3Libthreading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "D:/Test/Test4/main.py", line 57, in test
    loop = asyncio.get_event_loop()
  File "D:Anaconda3Libasyncioevents.py", line 639, in get_event_loop
    raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-1'.
 

Как я могу использовать asyncio в потоке?

Это очень важно для меня. Я два дня боролся с этой проблемой.

Я был бы признателен вам за помощь.

Ответ №1:

При использовании потока, отличного от основного потока, вам необходимо установить цикл событий

 def test():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(main())
    loop.close()
 

Ответ №2:

Если вам не нужно работать с уже существующим циклом событий (не в данном случае) или поддерживать Python 3.6, используйте asyncio.run вместо ручной обработки цикла:

 def test():
    asyncio.run(main())
 

Это всегда гарантирует наличие допустимого цикла событий, а также обеспечивает надлежащую очистку.

Эта функция всегда создает новый цикл событий и закрывает его в конце. Он должен использоваться в качестве основной точки входа для программ asyncio и в идеале должен вызываться только один раз.


Обратите внимание, что при объединении asyncio с потоками цикл событий обычно должен выполняться в основном цикле (см., например, bpo#34697). Вместо того , чтобы создавать поток для asyncio , предпочитайте создавать поток для синхронных частей вашей программы.

 # launch synchronous work in child threads
t=threading.Thread(target=my_sync_tasks)
t.start()

# launch asynchronous work in main thread
asyncio.run(main())
t.join()