我正在尝试将Python2.7代码重写为新的异步世界顺序:
def get_api_results(func, iterable):
pool = multiprocessing.Pool(5)
for res in pool.map(func, iterable):
yield res
map()
阻塞,直到计算完所有结果,所以我试图将其重写为一个异步实现,该实现将在结果就绪后立即生成结果。与map()
一样,返回值的顺序必须与iterable
相同。我试过这个(我需要requests
,因为旧的身份验证要求):
import requests
def get(i):
r = requests.get('https://example.com/api/items/%s' % i)
return i, r.json()
async def get_api_results():
loop = asyncio.get_event_loop()
futures = []
for n in range(1, 11):
futures.append(loop.run_in_executor(None, get, n))
async for f in futures:
k, v = await f
yield k, v
for r in get_api_results():
print(r)
但在Python3.6中,我得到了:
File "scratch.py", line 16, in <module>
for r in get_api_results():
TypeError: 'async_generator' object is not iterable
我怎样才能做到这一点?
关于旧的(2.7)代码,多处理被认为是一种强大的替代方法,它可以取代更简单的线程模块,用于并发处理CPU密集型任务,在这些任务中,线程工作得不太好。您的代码可能不受CPU限制—因为它只需要发出HTTP请求—线程可能已经足够解决您的问题了。
然而,Python 3+没有直接使用
threading
,而是有一个很好的模块,名为concurrent.futures,它通过coolExecutor
类使用更干净的API。此模块也可作为external package用于python 2.7。以下代码适用于Python2和Python3:
此代码基于线程使用
futures.ThreadPoolExecutor
。这里使用了很多魔法。上面的python 3.6代码使用^{} 来创建一个
futures.ProcessPoolExecutor()
,而不是真正使用异步IO!!如果您真的想继续使用asyncio,则需要使用支持asyncio的HTTP客户端,例如aiohttp。下面是一个示例代码:
如您所见,
asyncio
还有一个as_completed()
,现在使用真正的异步IO,在一个进程上只使用一个线程。你把你的事件循环放在另一个共同程序中。别那么做。事件循环是异步代码的最外层“驱动程序”,应该同步运行。
如果需要处理获取的结果,请编写更多这样做的协程。他们可以从队列中获取数据,也可以直接驱动获取。
您可以有一个获取和处理结果的主函数,例如:
我会使用类似于^{} 的异步库使
get()
函数正确地异步,这样您就不必使用执行器了。相关问题 更多 >
编程相关推荐