如何在python中选择异步或同步方法变量?

发布于 2021-01-29 17:30:29

假设我有一个用于执行I / O操作的类:

class CommunicationStack:
    def __init__(self, socket):
        self.socket = socket

    def sync_get_data(self):
        ...

    def sync_send_data(self):
        ...

    async def async_get_data(self):
        ...

    async def async_send_data(self):
        ...

如您所见,它具有用于相同操作的sync和async变体,但是编写async_get_datasync_get_data手动操作会稍有不便。我正在寻找一种具有相同界面的聪明方法

def get_data(self):
    ...  # call sync variant or return an awaitable, depending on caller type

def send_data(self):
    ...  # call sync variant or return an awaitable, depending on caller type

因此可以方便地像这样使用:

stack = CommunicationStack(...)

def thread_procedure():
    data = stack.get_data()  # get_data returns data

async def task_procedure():
    data = await stack.get_data()  # get_data returns an awaitable

我相信可以通过检查或一些黑魔法以某种棘手的方式完成:

def is_caller_coroutine():
    return sys._getframe(2).f_code.co_flags & 0x380

检查调用程序是协程还是函数,但是弄乱python的胆量似乎是一个糟糕的设计。


问题是:选择合适变体的好方法是什么?还是有更好的方法来设计一切都像使用适配器或开发两个独立AsyncCommunicationStackSyncCommunicationStack类?

关注者
0
被浏览
204
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    如果要以与常规函数相同的方式调用异步函数,则可能对使用gevent感兴趣。

    asyncio希望您将函数显式标记为,async并在await发生异步情况的任何地方显式使用。换句话说,asyncio希望您具有用于同步和异步代码的不同接口。

    这是为应对并发问题而做出的有意识的决定,当隐藏代码的异步特性时(例如在gevent中),很难实现。

    所以是的-
    如果您想同时支持两个世界,则可以采用两种不同的IndependentAsyncCommunicationStackCommunicationStackClass。虽然一旦有了异步版本,您就可以使用它强制转换关键代码,并通过asyncio.run()运行它使其同步。唯一的问题是那之后您将无法返回异步世界。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看