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

博客讨论了如何在类中同时提供同步和异步I/O操作的方法,以便根据调用者类型智能选择使用同步或异步版本。提出了使用两个独立的AsyncCommunicationStack和CommunicationStack类作为解决方案,尽管这可能引入额外的复杂性,但可以保持代码清晰。另外,建议一旦有了异步版本,可以使用asyncio.run()将关键代码同步执行,但这将限制返回到异步执行的能力。
摘要由CSDN通过智能技术生成

Let's assume I have a class that is used to perform I/O operations:

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):

...

As you can see it has sync and async variant for the same operations but it would be slightly inconvenient to write async_get_data or sync_get_data manually. I am looking for a smart way to have the same interface like

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

so it can be conveniently used like:

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

I believe it can be done in some tricky way with inspections or some black magic:

def is_caller_coroutine():

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

to check if caller is a coroutine or a function but it seems like a bad design to mess with python's guts.

The question is: what is a good way to choose appropriate variant? Or is there a better way to design everything like using adapters or developing two independent AsyncCommunicationStack and SyncCommunicationStack classes?

解决方案

If you want to call async functions same way as regular ones, you may be interested in using gevent.

asyncio wants you to explicitly mark functions as async and to explicitly use await everywhere async stuff happens. In other words asyncio wants you to have different interfaces for sync and async code.

This is intentional decision made to fight with concurrency problems which is much harder to achieve when async nature of a code is hidden (like in gevent).

So yes - two different independent AsyncCommunicationStack and CommunicationStack classes is a way to go if you want to support both worlds. Although once you have async version you can cast write critical code with it and make it sync just running it with asyncio.run(). Problem only is that you won't be able to return to async world after that.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值