async — sync — async

貓橘毛 aka Lanfon
4 min readApr 2, 2018

--

話說…不知道是要話說什麼總之看個 code 囧/

import asyncioasync def main():
pass
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

main 是個標準(?)的 async function ,

情境 A 是在 async function 裡面想要把 sync function 改成 async 來呼叫,會像這樣:

def sync_func():
pass # do something
async def main():
loop = asyncio.get_event_loop()
rv = await loop.run_in_executor(None, sync_func)
# do other thing

這算是蠻一般的情境, run_in_executor 支援 concurrent.futures 的兩種 Executor,預設(None)是用 ThreadPoolExecutor 。
(沒記錯的話在講 CPU-bound 的文裡面有講到)

情境B 是在 async function 裡面想要呼叫或識別 sync/async function,像是這樣:

async def main(callback):
rv = 1 # do something then got return value
coro = callback(rv)
# coro will be coroutine if callback is async function
if asyncio.iscoroutine(coro):
await coro

這個在 async libraries 裡面蠻常見的,直接支援 sync/async 的呼叫;不過這種判斷忽略了 callback 是 sync function 但回傳 Future 的情況。(可以用 asyncio.isfuture 來檢查)

情境C 是在 sync function 裡面想要呼叫 async function ,像這樣:

async def async_func():
pass # do something asynchronously
def do_sync():
# problem here

do_sync 裡會根據更上一層的情況有不同的解法,

一是不處在 event loop 裡的情況(就是外層沒有任何 asynchronous):

def do_sync():  # for situation C-1
loop = asyncio.get_event_loop()
val = loop.run_until_complete(async_func())
# do other thing

這個其實就是最一開始的範例(?!),沒有 event loop 的話生一個就好惹多簡單(X

二是處在 event loop 裡的情況:

def do_sync():  # for situation C-2
fut = concurrent.futures.Future()
def to_sync():
loop = asyncio.new_event_loop()
val = loop.run_until_complete(async_func())
loop.close()
fut.set_result(val)
threading.Thread(target=to_sync).start()
v = fut.result()

在這種情境下的實際問題是, Python 的 event loop 在運作的時候,每個「執行中」的 function 的 sync 操作都是獨佔的,就像是搶著 GIL 不放那樣;所以在 do_sync 裡面沒辦法把 async function 丟進去等它算完再回來[1],最簡單的解法就是在裡面開另一個 event loop 來執行 async function,然後用 concurrent.futures 的 Future 來傳遞回傳值[2]。

# 雖然我是覺得這種情況應該是設計上的錯誤啦….

[1] 這也是為什麼 async function 得用 await 或是 asyncio.ensure_future 丟到 loop 裡面工作的原因

[2] Thread 執行之後是不會有回傳值的,簡化傳值跟 Lock 之類最簡單的操作就是利用 Future 會 block 的特性

以上 94 今天的廢文,不知道之後其他人有問題的時候會不會找到這篇XDD

--

--

貓橘毛 aka Lanfon
貓橘毛 aka Lanfon

Written by 貓橘毛 aka Lanfon

知,不知,上;不知,知,病。

Responses (1)