假设我有这样一组函数:
def func1():
func2()
def func2():
time.sleep(1) # simulate I/O operation
print('done')
我希望这些可以同步使用:
# this would take two seconds to complete
func1()
func1()
以及异步,例如:
# this would take 1 second to complete
future = asyncio.gather(func1.run_async(), func1.run_async())
loop = asyncio.get_event_loop()
loop.run_until_complete(future)
当然,问题是func1
必须以某种方式将它运行的“上下文”(同步与异步)传播到func2
。你知道吗
我希望避免编写每个函数的异步变体,因为这样会导致大量重复代码:
def func1():
func2()
def func2():
time.sleep(1) # simulate I/O operation
print('done')
# duplicate code below...
async def func1_async():
await func2_async()
async def func2_async():
await asyncio.sleep(1) # simulate I/O operation
print('done')
有没有什么方法可以做到这一点而不必实现所有函数的异步拷贝?你知道吗
这是我的“没有答案”,我知道Stack Overflow喜欢。。。你知道吗
我认为没有。制作一个“一揽子翻译程序”将函数转换为本地协同程序似乎几乎是不可能的。这是因为使同步函数异步不仅仅是在它前面抛出一个
async
关键字和几个await
语句。你知道吗你的
def func2(): time.sleep(1)
说明了这一点。同步函数将进行阻塞调用,例如time.sleep()
;异步(本机协程)将等待非阻塞协程。正如您所指出的,使这个函数异步化不仅需要使用async def func()
,而且需要等待asyncio.sleep()
。现在让我们假设您调用的不是time.sleep()
,而是更复杂的阻塞函数。您构建了某种花哨的decorator,将名为run_async
的function attribute放在修饰函数上,这是一个可调用的函数。但是,如果定义了func2()
中的阻塞调用,那么修饰符如何知道如何将这些阻塞调用“转换”为它们的协同程序等价物呢?我想不出有什么魔法能聪明到将同步函数中的所有调用都转换成它们的await
可对应的调用。你知道吗在您的评论中,您提到这是针对HTTP请求的。对于一个真实的例子,
requests
和aiohttp
包之间的调用签名和api的差异。在aiohttp
中,.text()
是实例method;在requests
中,.text
是实例property。你怎么能建立一个足够聪明的东西来知道这样的区别呢?你知道吗我并不想让人沮丧,但我认为使用线程将更现实。你知道吗
所以我找到了一个方法来实现这一点,但是由于这是我第一次用
async
做任何事情,我不能保证这没有任何错误或者这不是一个糟糕的主意。你知道吗这个概念实际上非常简单:在必要的地方使用
async def
和await
像普通异步函数一样定义函数,然后在它们周围添加一个包装器,如果没有运行事件循环,它会自动等待函数。概念证明:然而,这种方法确实有其局限性。如果同步函数调用混合函数,则从异步函数调用同步函数将更改其行为:
小心点!你知道吗
相关问题 更多 >
编程相关推荐