<p>所以我找到了一个方法来实现这一点,但是由于这是我第一次用<code>async</code>做任何事情,我不能保证这没有任何错误或者这不是一个糟糕的主意。你知道吗</p>
<p>这个概念实际上非常简单:在必要的地方使用<code>async def</code>和<code>await</code>像普通异步函数一样定义函数,然后在它们周围添加一个包装器,如果</em>没有运行事件循环,它会自动等待函数。概念证明:</p>
<pre><code>import asyncio
import functools
import time
class Hybrid:
def __init__(self, func):
self._func = func
functools.update_wrapper(self, func)
def __call__(self, *args, **kwargs):
coro = self._func(*args, **kwargs)
loop = asyncio.get_event_loop()
if loop.is_running():
# if the loop is running, we must've been called from a
# coroutine - so we'll return a future
return loop.create_task(coro)
else:
# if the loop isn't running, we must've been called synchronously,
# so we'll start the loop and let it execute the coroutine
return loop.run_until_complete(coro)
def run_async(self, *args, **kwargs):
return self._func(*args, **kwargs)
@Hybrid
async def func1():
await func2()
@Hybrid
async def func2():
await asyncio.sleep(0.1)
def twice_sync():
func1()
func1()
def twice_async():
future = asyncio.gather(func1.run_async(), func1.run_async())
loop = asyncio.get_event_loop()
loop.run_until_complete(future)
for func in [twice_sync, twice_async]:
start = time.time()
func()
end = time.time()
print('{:>11}: {} sec'.format(func.__name__, end-start))
# output:
# twice_sync: 0.20142340660095215 sec
# twice_async: 0.10088586807250977 sec
</code></pre>
<p>然而,这种方法确实有其局限性。如果同步函数调用混合函数,则从异步函数调用同步函数将更改其行为:</p>
<pre><code>@hybrid
async def hybrid_function():
return "Success!"
def sync_function():
print('hybrid returned:', hybrid_function())
async def async_function():
sync_function()
sync_function() # this prints "Success!" as expected
loop = asyncio.get_event_loop()
loop.run_until_complete(async_function()) # but this prints a coroutine
</code></pre>
<p>小心点!你知道吗</p>