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

2024-09-30 16:35:43 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我相信这可以通过一些巧妙的方式来完成,比如检查或者一些black magic

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

检查调用者是一个协同程序还是一个函数,但这似乎是一个糟糕的设计,扰乱了python的胆量。你知道吗


问题是:选择合适的变体的好方法是什么?或者有没有更好的方法来设计所有的东西,比如使用adapters或者开发两个独立的AsyncCommunicationStackSyncCommunicationStack类?你知道吗


Tags: selfansenddatagetasyncreturnstack
1条回答
网友
1楼 · 发布于 2024-09-30 16:35:43

如果您想以与常规函数相同的方式调用异步函数,您可能会对使用gevent感兴趣。你知道吗

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

这是intentional decision用来解决并发问题的,当代码的异步特性被隐藏时(比如在gevent中),并发问题很难实现。你知道吗

所以是的-如果您想同时支持两个世界,两个不同的独立的AsyncCommunicationStackCommunicationStack类是一种方法。尽管一旦你有了异步版本,你就可以用它来强制转换写关键代码,并让它与asyncio.run()同步。唯一的问题是,在此之后您将无法返回到异步世界。你知道吗

相关问题 更多 >