91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python中的asyncio庫-函數的回調與調度

發布時間:2020-08-24 14:44:48 來源:億速云 閱讀:509 作者:Leah 欄目:編程語言

這篇文章運用簡單易懂的例子給大家介紹Python中的asyncio庫-函數的回調與調度,代碼非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

在大部分的高級語言中都有回調函數,這里我們看下asyncio中的的函數回調。

成功回調

可以給Task(Future)添加回調函數,等Task完成后就會自動調用這個(些)回調:

async def a():
    await asyncio.sleep(1)
    return 'A'
In : loop = asyncio.get_event_loop()
In : task = loop.create_task(a())
In : def callback(future):
...:     print(f'Result: {future.result()}')
...:
In : task.add_done_callback(callback)
In : await task
Result: A
Out: 'A'

可以看到在任務完成后執行了callback函數。我這里順便解釋一個問題,不知道有沒有人注意到。

為什么之前一直推薦大家用asyncio.create_task,但是很多例子卻用了loop.create_task?

這是因為在IPython里面支持方便的使用await執行協程,但如果直接用asyncio.create_task會報「no running event loop」:

In : asyncio.create_task(a())
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-2-2a742a8da161> in <module>
----> 1 asyncio.create_task(a())
/usr/local/lib/python3.7/asyncio/tasks.py in create_task(coro)
    322     Return a Task object.
    323     """
--> 324     loop = events.get_running_loop()
    325     return loop.create_task(coro)
    326
RuntimeError: no running event loop

Eventloop是在單進程里面的單線程中的,在IPython里面await的時候會把協程注冊到一個線程的Eventloop上,但是REPL環境是另外一個線程,不是一個線程,所以會提示這個錯誤,即便asyncio.events._set_running_loop(loop)設置了loop,任務可以創建倒是不能await:因為task是在線程X的Eventloop上注冊的,但是await時卻到線程Y的Eventloop上去執行。這部分是C實現的,可以看延伸閱讀鏈接1。

所以現在你就會看到很多loop.create_task的代碼片段,別擔心,在代碼項目里面都是用asyncio.create_task的,如果你非常想要在IPython里面使用asyncio.create_task也不是沒有辦法,可以這樣做:

In : loop = asyncio.get_event_loop()
In : def loop_runner(coro):
...:     asyncio.events._set_running_loop(None)
...:     loop.run_until_complete(coro)
...:     asyncio.events._set_running_loop(loop)
...:
In : %autoawait loop_runner
In : asyncio.events._set_running_loop(loop)
In : task = asyncio.create_task(a())
In : await task
Out: 'A'

這樣就可以啦。我解釋下為什么:

IPython里面能運行await是由于loop_runner函數,這個函數能運行協程(延伸閱讀鏈接2),默認的效果大概是asyncio.get_event_loop().run_until_complete(coro)。為了讓asyncio.create_task正常運行我定義了新的loop_runner

通過autoawait這個magic函數就可以重新設置loop_runner

上面的報錯是「no running event loop」,所以通過events._set_running_loop(loop)設置一個正在運行的loop,但是在默認的loop_runner中也無法運行,會報「Cannot run the event loop while another loop is running」,所以重置await里面那個running的loop,運行結束再設置回去。

如果你覺得有必要,可以在IPython配置文件中設置這個loop_runner到c.InteractiveShell.loop_runner上~

好,我們說回來,add_done_callback方法也是支持參數的,但是需要用到functools.partial:

def callback2(future, n):
    print(f'Result: {future.result()}, N: {n}')
In : task = loop.create_task(a())
In : task.add_done_callback(partial(callback2, n=1))
In : await task
Result: A, N: 1
Out: 'A'

調度回調

asyncio提供了3個按需回調的方法,都在Eventloop對象上,而且也支持參數:

call_soon

在下一次事件循環中被回調,回調是按其注冊順序被調用的:

def mark_done(future, result):
    print(f'Set to: {result}')
    future.set_result(result)
async def b1():
    loop = asyncio.get_event_loop()
    fut = asyncio.Future()
    loop.call_soon(mark_done, fut, 'the result')
    loop.call_soon(partial(print, 'Hello', flush=True))
    loop.call_soon(partial(print, 'Greeting', flush=True))
    print(f'Done: {fut.done()}')
    await asyncio.sleep(0)
    print(f'Done: {fut.done()}, Result: {fut.result()}')
In : await b1()
Done: False
Set to: the result
Hello
Greeting
Done: True, Result: the result

這個例子輸出的比較復雜,我挨個分析:

call_soon可以用來設置任務的結果: 在mark_done里面設置

通過2個print可以感受到call_soon支持參數。

最重要的就是輸出部分了,首先fut.done()的結果是False,因為還沒到下個事件循環,sleep(0)就可以切到下次循環,這樣就會調用三個call_soon回調,最后再看fut.done()的結果就是True,而且fut.result()可以拿到之前在mark_done設置的值了

call_later

安排回調在給定的時間(單位秒)后執行:

async def b2():
    loop = asyncio.get_event_loop()
    fut = asyncio.Future()
    loop.call_later(2, mark_done, fut, 'the result')
    loop.call_later(1, partial(print, 'Hello'))
    loop.call_later(1, partial(print, 'Greeting'))
    print(f'Done: {fut.done()}')
    await asyncio.sleep(2)
    print(f'Done: {fut.done()}, Result: {fut.result()}')
In : await b2()
Done: False
Hello
Greeting
Set to: the result
Done: True, Result: the result

這次要注意3個回調的延遲時間時間要<=sleep的,要不然還沒來及的回調程序就結束了

call_at

安排回調在給定的時間執行,注意這個時間要基于 loop.time() 獲取當前時間:

async def b3():
    loop = asyncio.get_event_loop()
    now = loop.time()
    fut = asyncio.Future()
    loop.call_at(now + 2, mark_done, fut, 'the result')
    loop.call_at(now + 1, partial(print, 'Hello', flush=True))
    loop.call_at(now + 1, partial(print, 'Greeting', flush=True))
    print(f'Done: {fut.done()}')
    await asyncio.sleep(2)
    print(f'Done: {fut.done()}, Result: {fut.result()}')
In : await b3()
Done: False
Hello
Greeting
Set to: the result
Done: True, Result: the result

關于Python中的asyncio庫-函數的回調與調度就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

元朗区| 西峡县| 土默特左旗| 宣城市| 肃北| 辽阳县| 北安市| 黄山市| 慈溪市| 当阳市| 炉霍县| 博白县| 新蔡县| 湘阴县| 卫辉市| 澜沧| 广水市| 汪清县| 西乡县| 来凤县| 黎城县| 礼泉县| 哈巴河县| 盐边县| 本溪| 常州市| 凭祥市| 哈密市| 怀来县| 射阳县| 瓦房店市| 徐闻县| 寻乌县| 唐河县| 花垣县| 南阳市| 怀仁县| 城固县| 德兴市| 广西| 中牟县|