2016-11-29 38 views
3

假設我們有一些IO操作的異步調用,我們想記錄它。 最簡單的方法是這樣的:記錄異步調用的正確/常用方式

async def f(): 
    logger.log('io was called') 
    await call_some_io() 

但我們當我們運行log()功能,切換的情況下,並記錄別的東西,只有這樣執行call_some_io()後明顯可以打的情況。

下一頁方法看起來更健壯:

async def f(): 
    await call_some_io() 
    logger.log('io was called') 

我們正在等待call_some_io()和後我們會記錄它。看起來在這種情況下,我們有一致的呼叫。

但有使用上下文管理第三種方式:

async def f(): 
    with LoggingContext: 
    await call_some_io() 

而這裏LoggingContext一些ContextManager其中__exit__方法有一些記錄電話。

所以問題是:哪種方法來記錄異步調用是最常見和強大的?

回答

2

所有的方法都很健壯。上下文管理器可能並不常見,但仍然很強大。

但是,示例#1和#2具有不同的語義。第一條日誌消息應爲about to call io而不是io was called,因爲尚未發出任何調用。

LoggingContext示例對於開發人員來說相當方便,但在執行順序方面等於示例#2。

+0

好的,謝謝!它們中最常見的是什麼? – Paul

+0

我只能爲自己說話,我會在執行操作後記錄消息,除非操作需要很長時間。 – Fabian

0

在啓動另一個協程的協程中使用日誌記錄相對健壯,因爲您已經注意到可能會發生上下文切換。實際上只有兩種情況:在等待之前和之後以及幾種可能的方法:登錄協程,記錄裝飾器和記錄上下文管理器。我相信這不是一個詳盡的清單。

記錄協程內部IO開始

async def coro(): 
    logger.log('Before io start') 
    await call_some_io() 

前IO開始

def logger(f): 
    def warp(*arguments, **kwarguments): 
     logging.log("Before io start") 
     f(*arguments. **kwarguments) 
    return wrap 

@logger 
async def coro(): 
    # Async logic... 

測井上下文經理IO開始

之前登錄其登錄裝飾器之前登錄
class Logger(object): 
    def __enter__(self): 
     logging.log("Before io start") 

    # Empty __exit__ ... 

with Logger(): 
    await coro() 

在io調用之後記錄的修飾器的一個更棘手的示例。

def logger(f):   
    async def wrapper(): 
     await f()  
     logging.log("After io start") 
    return wrapper 

裝飾器的包裝必須是協程,以便在io啓動後記錄異步調用。使用異步記錄器登錄異步調用絕對不是很健壯;)

在調用之後很容易將日內和管理器方法轉變爲日誌記錄,因此我將跳過一個示例。

所有這些例子都是同樣常見的,因爲Python非常具有藝術性,並且沒有像Java那樣的編程模式。所以所有的方法看起來像Pythonic對我來說。