programing

런타임 오류:비동기 + apscheduler의 스레드에 현재 이벤트 루프가 없습니다.

minimums 2023. 5. 13. 09:23
반응형

런타임 오류:비동기 + apscheduler의 스레드에 현재 이벤트 루프가 없습니다.

저는 비동기 기능을 가지고 있고 N분마다 일정관리자와 함께 실행해야 합니다.아래에 파이썬 코드가 있습니다.

URL_LIST = ['<url1>',
            '<url2>',
            '<url2>',
            ]

def demo_async(urls):
    """Fetch list of web pages asynchronously."""
    loop = asyncio.get_event_loop() # event loop
    future = asyncio.ensure_future(fetch_all(urls)) # tasks to do
    loop.run_until_complete(future) # loop until done

async def fetch_all(urls):
    tasks = [] # dictionary of start times for each url
    async with ClientSession() as session:
        for url in urls:
            task = asyncio.ensure_future(fetch(url, session))
            tasks.append(task) # create list of tasks
        _ = await asyncio.gather(*tasks) # gather task responses

async def fetch(url, session):
    """Fetch a url, using specified ClientSession."""
    async with session.get(url) as response:
        resp = await response.read()
        print(resp)

if __name__ == '__main__':
    scheduler = AsyncIOScheduler()
    scheduler.add_job(demo_async, args=[URL_LIST], trigger='interval', seconds=15)
    scheduler.start()
    print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))

    # Execution will block here until Ctrl+C (Ctrl+Break on Windows) is pressed.
    try:
        asyncio.get_event_loop().run_forever()
    except (KeyboardInterrupt, SystemExit):
        pass

그러나 실행하려고 시도했을 때 다음 오류 정보가 있습니다.

Job "demo_async (trigger: interval[0:00:15], next run at: 2017-10-12 18:21:12 +04)" raised an exception.....
..........\lib\asyncio\events.py", line 584, in get_event_loop
    % threading.current_thread().name)
RuntimeError: There is no current event loop in thread '<concurrent.futures.thread.ThreadPoolExecutor object at 0x0356B150>_0'.

이것 좀 도와주시겠어요?Python 3.6, APScheduler 3.3.1,

당신의def demo_async(urls)교체 시도:

loop = asyncio.get_event_loop()

포함:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

언급되지 않은 중요한 것은 오류가 발생하는 이유입니다.개인적으로, 오류가 발생하는 이유를 아는 것은 실제 문제를 해결하는 것만큼이나 중요합니다.

이제 다음의 구현을 살펴보겠습니다.get_event_loopBaseDefaultEventLoopPolicy:

class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy):
    ...

    def get_event_loop(self):
        """Get the event loop.

        This may be None or an instance of EventLoop.
        """
        if (self._local._loop is None and
            not self._local._set_called and
            isinstance(threading.current_thread(), threading._MainThread)):
            self.set_event_loop(self.new_event_loop())
        if self._local._loop is None:
            raise RuntimeError('There is no current event loop in thread %r.'
                               % threading.current_thread().name)
        return self._local._loop

당신은 그것을 볼 수 있습니다.self.set_event_loop(self.new_event_loop())는 다음 조건이 모두 충족되는 경우에만 실행됩니다.

  • self._local._loop is None-_local._loop설정되지 않음
  • not self._local._set_called-set_event_loop아직 호출되지 않았습니다.
  • isinstance(threading.current_thread(), threading._MainThread)현재 스레드가 메인 스레드입니다(이 경우는 사실이 아닙니다).

따라서 현재 스레드에 루프가 설정되지 않았기 때문에 예외가 발생합니다.

if self._local._loop is None:
    raise RuntimeError('There is no current event loop in thread %r.'
                       % threading.current_thread().name)

그냥 지나침fetch_all로.scheduler.add_job()직접적으로.비동기 스케줄러는 작업 대상으로 코루틴 기능을 지원합니다.

대상 호출 가능한 함수가 코루틴 함수가 아닌 경우 (과거의 이유로) 작업자 스레드에서 실행되므로 예외입니다.

비슷한 문제가 있었습니다. 비동기식 모듈을 비동기식 스크립트가 아닌 스크립트에서 호출할 수 있어야 했습니다(사건으로 실행 중...).묻지 마...)아래 코드는 현재 이벤트 루프를 가져오려고 하지만 현재 스레드에 이벤트 루프가 없으면 루프를 만들기 때문에 문제를 해결했습니다.python 3.9.11에서 테스트되었습니다.

try:
    loop = asyncio.get_event_loop()
except RuntimeError as e:
    if str(e).startswith('There is no current event loop in thread'):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
    else:
        raise

사용하다asyncio.run()이벤트 루프를 직접 사용하는 대신.새 루프를 만들고 완료되면 루프를 닫습니다.

'실행'은 다음과 같습니다.

if events._get_running_loop() is not None:
    raise RuntimeError(
        "asyncio.run() cannot be called from a running event loop")

if not coroutines.iscoroutine(main):
    raise ValueError("a coroutine was expected, got {!r}".format(main))

loop = events.new_event_loop()
try:
    events.set_event_loop(loop)
    loop.set_debug(debug)
    return loop.run_until_complete(main)
finally:
    try:
        _cancel_all_tasks(loop)
        loop.run_until_complete(loop.shutdown_asyncgens())
    finally:
        events.set_event_loop(None)
        loop.close()

이 질문은 계속 첫 페이지에 뜨기 때문에, 저는 여기에 저의 문제와 저의 대답을 쓸 것입니다.

나는.RuntimeError: There is no current event loop in thread 'Thread-X'.플라스크-소켓리오스칸디나비아를 사용하는 경우.


편집: 글쎄요, 저는 제 파일을 리팩터링하고 수업을 만들었습니다.

생성자의 루프를 초기화했고 이제 모든 것이 정상적으로 작동합니다.

class BLE:
    def __init__(self):
        self.loop = asyncio.get_event_loop()

    # function example, improvement of
    # https://github.com/hbldh/bleak/blob/master/examples/discover.py :
    def list_bluetooth_low_energy(self) -> list:
        async def run() -> list:
            BLElist = []
            devices = await bleak.discover()
            for d in devices:
                BLElist.append(d.name)
            return 'success', BLElist
        return self.loop.run_until_complete(run())

용도:

ble = path.to.lib.BLE()
list = ble.list_bluetooth_low_energy()

원답:

그 해결책은 어리석었습니다.나는 내가 한 일에 주의를 기울이지 않았지만, 몇몇은 옮겼습니다.import다음과 같은 기능을 사용합니다.

import asyncio, platform
from bleak import discover

def listBLE() -> dict:
    async def run() -> dict:
        # my code that keep throwing exceptions.

    loop = asyncio.get_event_loop()
    ble_list = loop.run_until_complete(run())
    return ble_list

그래서 저는 제 코드에서 무언가를 변경해야 한다고 생각했고, 저는 줄 바로 앞에 있는 이 코드 조각을 사용하여 새로운 이벤트 루프를 만들었습니다.get_event_loop():

loop = asyncio.new_event_loop()
loop = asyncio.set_event_loop()

이 순간 저는 매우 행복했습니다. 제가 루프를 실행했기 때문입니다.

하지만 응답하지 않습니다.그리고 제 코드는 몇 가지 값을 반환하는 데 시간 제한이 필요했기 때문에 제 앱에 상당히 좋지 않았습니다.

그 문제가 문제였다는 것을 알아내는 데 거의 두 시간이 걸렸습니다.import여기 제 (작동) 코드가 있습니다.

def list() -> dict:
    import asyncio, platform
    from bleak import discover

    async def run() -> dict:
        # my code running perfectly

    loop = asyncio.get_event_loop()
    ble_list  = loop.run_until_complete(run())
    return ble_list

주어진 답변을 읽으면서 저는 이 페이지의 https://stackoverflow.com/a/46750562/598513 에 있는 힌트(교체 시도)를 사용하여 웹 소켓 스레드를 수정할 수 있었습니다.

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

『 』의 BaseDefaultEventLoopPolicy

이벤트 루프에 액세스하기 위한 기본 정책 구현.이 정책에서는 각 스레드에 고유한 이벤트 루프가 있습니다.그러나 기본적으로 기본 스레드에 대한 이벤트 루프만 자동으로 생성합니다. 다른 스레드에는 기본적으로 이벤트 루프가 없습니다.

그래서 스레드를 사용할 때는 루프를 생성해야 합니다.

그리고 코드를 다시 정렬해야 했기 때문에 마지막 코드는

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    # !!! Place code after setting the loop !!!
    server = Server()
    start_server = websockets.serve(server.ws_handler, 'localhost', port)

저 같은 경우는 이렇게 줄을 섰어요.

asyncio.get_event_loop().run_until_complete(test())

위 라인을 이 라인으로 교체하여 문제를 해결했습니다.

asyncio.run(test())

언급URL : https://stackoverflow.com/questions/46727787/runtimeerror-there-is-no-current-event-loop-in-thread-in-async-apscheduler

반응형