2016-08-09 7 views
4

저는 python3을 사용하여 응용 프로그램을 작성 중이며 asyncio를 처음 사용하려고합니다. 내가 만난 한 가지 문제점은 내 coroutines 중 일부가 이벤트 루프를 내가 좋아하는 것보다 오래 차단한다는 것입니다. 나는 얼마나 많은 벽/CPU 시간이 각 coroutines의 각각을 달리는 데 쓰이고 있는지를 보여줄 이벤트 루프를 위해 꼭대기를 따라 무언가를 찾으려고 노력하고있다. 이미 존재하는 것이 없다면 누구나 이벤트 루프에 후크를 추가하여 측정을 할 수있는 방법을 알고 있습니까?asyncio 이벤트 루프 모니터링

일부 유용한 출력을 제공하는 cProfile을 사용해 보았지만 전체 실행 시간보다는 이벤트 루프를 차단하는 데 더 많은 시간을 보냈습니다.

답변

4

coroutines가 실행하는 데 많은 CPU 시간이 소요되는지 이벤트 루프에서 이미 추적 할 수 있습니다. 그것을보고 당신이 set_debug 방법 enable debug mode해야합니다 : 출력에서 ​​

import asyncio 
import time 


async def main(): 
    time.sleep(1) # Block event loop 


if __name__ == "__main__": 
    loop = asyncio.get_event_loop() 
    loop.set_debug(True) # Enable debug 
    loop.run_until_complete(main()) 

당신이 볼 수 있습니다 : 기본적으로

Executing <Task finished coro=<main() [...]> took 1.016 seconds 

그것은 코 루틴에 대한 경고를 보여줍니다 0.1 초 블록. 설명되어 있지 않지만 asyncio source code을 기반으로하면 slow_callback_duration 속성을 변경하여이 값을 수정할 수있는 것 같습니다.

1

call_later을 사용할 수 있습니다. 루프의 시간 및주기 간격 시간의 차이를 기록/알려주는 콜백을 주기적으로 실행합니다.

class EventLoopDelayMonitor: 

    def __init__(self, loop=None, start=True, interval=1, logger=None): 
     self._interval = interval 
     self._log = logger or logging.getLogger(__name__) 
     self._loop = loop or asyncio.get_event_loop() 
     if start: 
      self.start() 

    def run(self): 
     self._loop.call_later(self._interval, self._handler, self._loop.time()) 

    def _handler(self, start_time): 
     delay = (self._loop.time() - start_time) - self._interval 
     self._log.error('EventLoop delay %.4f', latency) 
     if not self.is_stopped(): 
      self.run() 

    def is_stopped(self): 
     return self._stopped 

    def start(self): 
     self._stopped = False 
     self.run() 

    def stop(self): 
     self._stopped = True 

예를

import time 

async def main(): 
    EventLoopDelayMonitor(interval=1) 
    await asyncio.sleep(1) 
    time.sleep(2) 
    await asyncio.sleep(1) 
    await asyncio.sleep(1) 

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

출력이 이 중단을 감지 루프 모니터링 할 경우

EventLoop delay 0.0013 
EventLoop delay 1.0026 
EventLoop delay 0.0014 
EventLoop delay 0.0015 
0

이 답변 중 하나에 비트를 확장하려면, 여기에 조각입니다 그냥해라. 루프 태스크가 최근 실행을 산출했는지 여부를 확인하는 별도의 스레드를 시작합니다.

def monitor_loop(loop, delay_handler): 
loop = loop 
last_call = loop.time() 

INTERVAL = .5 # How often to poll the loop and check the current delay. 
def run_last_call_updater(): 
    loop.call_later(INTERVAL, last_call_updater) 
def last_call_updater(): 
    nonlocal last_call 
    last_call = loop.time() 
    run_last_call_updater() 
run_last_call_updater() 

def last_call_checker(): 
    threading.Timer(INTERVAL/2, last_call_checker).start() 
    if loop.time() - last_call > INTERVAL: 
     delay_handler(loop.time() - last_call) 
threading.Thread(target=last_call_checker).start()