[英]How to generalize a function call which may be async, tornado coroutine, or normal?
我有一個具有多個配置庫的應用程序:
目前,我的代碼幾乎對所有這三個都完全相同,但是在調用每個函數調用的方式上卻有微小的差異。 這意味着我有大量的代碼重復,因為在許多地方都有類似以下的內容:
#Python2.7native.py
def main(client):
client.foo(args)
client.bar(args)
#Python2.7tornado.py
@gen.coroutine
def main(client):
yield client.foo(args)
yield client.bar(args)
#Python3.5asyncio.py
async def main(client):
await client.foo(args)
await client.bar(args)
其中client
是特定於語言的實現,分別支持本機python,asyncio和Tornado。 API方法調用是相同的。
我希望能夠以某種方式將其概括為可以包含在共享文件中的單個方法,該方法可以適當地調用各種方法
我曾考慮過在一個單獨的文件中定義方法,並使用getattr
正確調用測試,但這似乎很混亂。
有什么好方法嗎?
您不能在一個函數中完成所有這些操作client.foo()
應該如何知道是從“常規”同步應用程序中調用它,還是其調用者將使用yield
或await
。 但是,只要您願意將Tornado作為依賴項,就可以避免將所有代碼重復三次。
在一個模塊client_async.py
,使用Tornado的@gen.coroutine
實現您的功能:
@gen.coroutine
def foo(args):
yield something()
yield something_else()
raise gen.Return(another_thing())
在另一個client_sync.py
,將來自client_async.py
每個函數包裝在IOLoop.run_sync()
,以實現線程本地的IOLoop,如下所示:
import client_async
import threading
import tornado.ioloop
class _LocalIOLoop(threading.local):
def __init__(self):
self.value = tornado.ioloop.IOLoop()
local_ioloop = _LocalIOLoop()
def foo(args):
return local_ioloop.value.run_sync(lambda: foo_async.my_func(args))
現在,您可以在所有三個環境中使用此代碼。 從正常的同步代碼:
import client_sync
def main():
x = client_sync.foo(args)
從龍卷風@gen.coroutine
:
import client_async
@gen.coroutine
def main():
x = yield client_async.foo(args)
從async def
和asyncio
(請注意,這兩個不是同義詞-可以在不使用asyncio
情況下將asyncio
與async def
一起使用):
# one-time initialization for Tornado/asyncio integration
import tornado.platform.asyncio
tornado.platform.asyncio.AsyncIOMainLoop().install()
import client_async
async def main():
x = await client_async.foo(args)
使用@gen.coroutine
和yield
:這將在所有Python版本中工作。 用gen.coroutine
裝飾的功能比本地協程要慢一些,但是可以在所有相同的情況下使用。
對於同步情況,請使用run_sync
:
result = IOLoop.current().run_sync(main)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.