Python3.5Async/await与真实代码示例
我已经阅读了大量关于Python 3.5异步/等待的文章和教程。我不得不说我很困惑,因为有些人使用get_event_loop()并运行_直到_complete(),有些人使用sure_future(),有些人使用asyncio.wait(),还有一些人使用call_soon() 看起来我有很多选择,但我不知道它们是否完全相同,或者有些情况下使用循环,有些情况下使用wait() 但问题是,所有示例都使用Python3.5Async/await与真实代码示例,python,asynchronous,async-await,python-3.5,python-asyncio,Python,Asynchronous,Async Await,Python 3.5,Python Asyncio,我已经阅读了大量关于Python 3.5异步/等待的文章和教程。我不得不说我很困惑,因为有些人使用get_event_loop()并运行_直到_complete(),有些人使用sure_future(),有些人使用asyncio.wait(),还有一些人使用call_soon() 看起来我有很多选择,但我不知道它们是否完全相同,或者有些情况下使用循环,有些情况下使用wait() 但问题是,所有示例都使用asyncio.sleep()模拟返回等待对象的真正慢速操作。一旦我试图用这行代码替换一些真正
asyncio.sleep()
模拟返回等待对象的真正慢速操作。一旦我试图用这行代码替换一些真正的代码,整个事情就失败了。上面写的方法之间的区别是什么?我应该如何运行一个还没有准备好异步/等待的第三方库。我确实使用Quandl服务获取一些股票数据
import asyncio
import quandl
async def slow_operation(n):
# await asyncio.sleep(1) # Works because it's await ready.
await quandl.Dataset(n) # Doesn't work because it's not await ready.
async def main():
await asyncio.wait([
slow_operation("SIX/US9884981013EUR4"),
slow_operation("SIX/US88160R1014EUR4"),
])
# You don't have to use any code for 50 requests/day.
quandl.ApiConfig.api_key = "MY_SECRET_CODE"
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
我希望你能明白我是多么迷茫,我希望并行运行是多么简单。如果第三方库与
async/await
不兼容,那么显然你无法轻松使用它。有两种情况:
def fn(..., clb):
...
因此,您可以:
def on_result(...):
...
fn(..., on_result)
在这种情况下,您可以将此类函数包装到asyncio协议中,如下所示:
from asyncio import Future
def wrapper(...):
future = Future()
def my_clb(...):
future.set_result(xyz)
fn(..., my_clb)
return future
import asyncio
import time
from concurrent.futures import ThreadPoolExecutor
# Initialize 10 threads
THREAD_POOL = ThreadPoolExecutor(10)
def synchronous_handler(param1, ...):
# Do something synchronous
time.sleep(2)
return "foo"
# Somewhere else
async def main():
loop = asyncio.get_event_loop()
futures = [
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
]
await asyncio.wait(futures)
for future in futures:
print(future.result())
with THREAD_POOL:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
(使用future.set_异常(exc)
on异常)
然后,您可以使用await
在一些async
函数中调用该包装器:
value = await wrapper(...)
请注意,await
适用于任何Future
对象。您不必将wrapper
声明为async
from asyncio import Future
def wrapper(...):
future = Future()
def my_clb(...):
future.set_result(xyz)
fn(..., my_clb)
return future
import asyncio
import time
from concurrent.futures import ThreadPoolExecutor
# Initialize 10 threads
THREAD_POOL = ThreadPoolExecutor(10)
def synchronous_handler(param1, ...):
# Do something synchronous
time.sleep(2)
return "foo"
# Somewhere else
async def main():
loop = asyncio.get_event_loop()
futures = [
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
]
await asyncio.wait(futures)
for future in futures:
print(future.result())
with THREAD_POOL:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
但是请注意,将同步库与异步一起使用可能是个坏主意。您不会得到太多,但会使代码复杂化。您可以从中查看以下简单的工作示例。顺便说一下,它返回一个值得读取的字符串:-)
@grafa我的错,我没有测试代码。我现在已经修好了,并且简化了很多。实际上Python有一个整洁的
.run\in\u executor
函数,负责返回值和异常处理。无需手动执行。@grafa请注意,如果您安排的任务超过线程池的大小,则这些任务将排队等待线程。@grafa还请记住,之后必须关闭executor。请在此处阅读更多信息:@grafa首先安排调用,然后可以使用asyncio.wait()
等待所有调用。最后,您可以通过调用future.result()
来循环futures并检索结果。请参阅更新的代码。请注意,.run\u in\u executor
已经返回了一个未来的对象,不需要包装它。非常感谢。每个想法都有效,我想我知道整个事情。您是这个星球上第一个提供了如何将Python 3.5 async/await用于经典非异步任务的复杂示例的人。再次感谢!