2016-08-09 9 views
4

私はpython3を使用してアプリケーションを作成しており、初めてasyncioを試しています。私が遭遇した1つの問題は、私のコルーチンのいくつかがイベントループを私が好きなものより長くブロックすることです。私は、各ループのコルーチンを実行するのにどれくらいの時間が費やされているかを示すイベントループのトップラインに沿って何かを見つけようとしています。すでに存在するものがない場合は、誰かがイベントループにフックを追加して測定を行う方法を知っていますか?asyncioイベントループの監視

私はいくつかの有用な出力を提供するcProfileを使用しようとしましたが、私は、実行時間全体ではなく、イベントループをブロックするために費やした時間にもっと興味があります。

答えて

4

イベントループは、コルーチンが実行に多くの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

あなたがループを監視したい場合は、答えの1にビットを拡張し、ハングを検出するためには、ここに抜粋ですちょうどそれをしなさい。ループのタスクが最近実行されたかどうかをチェックする別のスレッドを起動します。

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()