[英]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.