python - 如何在Python中选择异步或同步方法变体?

标签 python asynchronous python-asyncio

假设我有一个用于执行 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):
        ...

正如您所看到的,它对于相同的操作有同步和异步变体,但手动编写 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

我相信这可以通过检查或一些棘手的方式来完成black magic :

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

检查调用者是协程还是函数,但这似乎是一个糟糕的设计,会扰乱Python的内部结构。

<小时/>

问题是:选择合适变体的好方法是什么?或者是否有更好的方法来设计一切,例如使用 adapters或者开发两个独立的 AsyncCommunicationStackSyncCommunicationStack 类?

最佳答案

如果您想以与常规函数相同的方式调用异步函数,您可能有兴趣使用 gevent .

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

这是intentional decision旨在解决并发问题,当隐藏代码的异步性质时(例如在 gevent 中),实现并发问题要困难得多。

所以是的 - 如果您想支持这两个世界,两个不同的独立 AsyncCommunicationStackCommunicationStack 类是一种可行的方法。尽管一旦有了异步版本,您就可以用它编写关键代码并使其同步,只需使用 asyncio.run() 运行它即可。 。唯一的问题是,此后您将无法返回异步世界。

关于python - 如何在Python中选择异步或同步方法变体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56524743/

相关文章:

python - 绑定(bind)错误: Unable to find a consistent port for localhost

python - OpenCV VideoWriter自动编解码器选择

python - 从具有以特定单词开头的索引的 Pandas 系列中删除元素

objective-c - 用 GCD 替换 performSelectorInBackground

python - 如何处理错误引发 - Python3 中的 Asyncio

python - 列表中的负面和正面

python - 在 WSGI 容器中使用扭曲的词

javascript - 如何模拟我的 api 调用函数中的延迟?

python - 在 asyncio add_done_callback 回调中访问上下文变量

python-3.x - 为什么这个异常会立即从 asyncio 任务中引发?