#python #multithreading #python-asyncio #python-logging
Вопрос:
Я пытался использовать библиотеку веб-сокетов python для создания клиента для сервера веб-сокетов и столкнулся с ошибкой, которую я не смог исправить.
При регистрации объекта, использующего библиотеку asyncio, скрипт просто останавливается, казалось бы, без всякой причины.
Это не является чем-то критичным, но это беспокоит меня, и я не хочу, чтобы это вызвало проблемы в будущем.
Вот пример кода, который воспроизводит это:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import asyncio
import logging
from threading import Thread
logger = logging.getLogger(__name__)
class Main(Thread):
def __init__(self):
Thread.__init__(self, daemon=True)
self.loop = asyncio.get_event_loop()
self.running = True
logger.debug("Init")
def run(self):
""" Starts the main loop in the thread """
logger.debug("Thread Started")
asyncio.set_event_loop(self.loop)
# self.main_task = asyncio.run_coroutine_threadsafe(
# self._mainloop(), self.loop)
# self.loop.run_forever()
self.loop.run_until_complete(self._mainloop())
logger.debug("Thread Finished")
async def _mainloop(self):
""" Async main loop """
while self.running:
await self.wait(0.1, "_mainloop")
logger.debug("Test loop")
async def wait(self, t, text):
""" Example async function """
logger.debug("Wait... %s", text)
await asyncio.sleep(t)
logger.debug("Wait ok %s", text)
return "Main object"
def __repr__(self):
""" Uses an async function to get the repr """
fut = asyncio.run_coroutine_threadsafe(
self.wait(0, "__repr__"), self.loop)
return fut.result()
def close(self):
""" Waits for the main loop to end """
logger.debug("Closing...")
self.running = False
self.join()
# self.main_task.result()
logger.debug("Closing ok")
if __name__ == "__main__":
FORMAT = '%(name)-8s %(threadName)-10s %(levelname)-8s %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)
logger.info("Start")
m = Main()
m.start()
logger.info("1 %s", repr(m)) # Works fine
logger.info("2 %s", str(m)) # Works fine
logger.info("3 %s" % m) # Works fine
logger.info("4 %s", m) # Halts
logger.info(str(m)) # Works fine
logger.info(m) # Also halts
m.close()
logger.info("End")
Вывод до точки остановки:
__main__ MainThread INFO Start
asyncio MainThread DEBUG Using proactor: IocpProactor
__main__ MainThread DEBUG Init
__main__ Thread-1 DEBUG Thread Started
__main__ Thread-1 DEBUG Wait... _mainloop
__main__ Thread-1 DEBUG Wait... __repr__
__main__ Thread-1 DEBUG Wait ok __repr__
__main__ MainThread INFO 1 Main object
__main__ Thread-1 DEBUG Wait... __repr__
__main__ Thread-1 DEBUG Wait ok __repr__
__main__ MainThread INFO 2 Main object
__main__ Thread-1 DEBUG Wait... __repr__
__main__ Thread-1 DEBUG Wait ok __repr__
__main__ MainThread INFO 3 Main object
С двумя прокомментированными блокирующими строками сценарий продолжается:
__main__ MainThread INFO 3 Main object
__main__ MainThread DEBUG Closing...
__main__ Thread-1 DEBUG Wait ok _mainloop
__main__ Thread-1 DEBUG Test loop
__main__ Thread-1 DEBUG Thread Finished
__main__ MainThread DEBUG Closing ok
__main__ MainThread INFO End
Изучая исходный код журнала, я не смог найти ничего, что могло бы это объяснить.
https://github.com/python/cpython/blob/0bc17658f5724ce60c3f75acc01e7526f1720efe/Lib/logging/__init__.py#L365-L368
Я пробовал разные методы создания цикла событий asyncio, но это не имело никакого значения.
Есть ли какие — то проблемы с моим кодом? Является ли это правильным способом использования asyncio и потоковой передачи?
Я использую Python 3.9.6 и регистрирую 0.5.1.2, если это поможет.
Комментарии:
1. Возможно, проблема связана с блокировками в методе обработки обработчиков: github.com/python/cpython/blob/…