我很难组合异步生成器并实际运行它们。这是因为我发现运行它们的唯一方法是通过一个事件循环来返回iterable而不是生成器。让我用一个简单的例子来说明这一点:
假设我有一个google_search函数,它通过抓取来搜索google(我不是故意使用API)。它接受一个搜索字符串并返回搜索结果的生成器。此生成器不会在页面结束时结束,函数将继续转到下一页。因此,google_search函数返回一个可能几乎没完没了的生成器(从技术上讲,它总是结束的,但通常在google上搜索时,你可以获得数百万次的点击率)
def google_search(search_string):
# Basically uses requests/aiohttp and beautifulsoup
# to parse the resulting html and yield search results
# Assume this function works
......
好的,现在我想创建一个函数,它允许我迭代多个google_搜索生成器。我想要这样的东西:
^{pr2}$这样我就可以使用一个简单的for循环来展开google_搜索并得到结果。上面的代码运行得很好,但是对于任何数量相当大的搜索来说都是非常缓慢的。代码发送第一次搜索的请求,然后发送第二次搜索的请求,直到最后,它产生结果。我想加快速度。我的第一个想法是将google_搜索改为一个异步函数(我使用的是python3.6.3,可以使用await/async等)。这将创建一个异步生成器,这很好,但我只能在另一个异步函数或事件循环中运行它。并在事件循环中使用run_运行它,直到\u完成(循环聚集(…))返回结果列表,而不是普通生成器,这将破坏此目的,因为可能有太多的搜索结果无法保存在列表中。在
我怎样才能使google_搜索功能更快(最好使用异步代码,但任何东西都是受欢迎的)异步执行请求,而它仍然是一个普通的生成器? 提前谢谢!在
我将把我之前编写的解决方案粘贴在这里,因为我总是以这个问题结束,只是为了记住我以前已经解决过这个问题。在
它有输入注释,但我认为这是一个很好的解决方案。它的意思是以异步生成器作为键调用它,如果您有任何要等待的话,还有一个未来。在
^{pr2}$你可以找到我怎么用的github.com/txomon/abot. 在
接受的答案等待来自每个异步生成器的一个结果,然后再调用生成器。如果数据不以同样的速度出现,那可能是个问题。下面的解决方案采用多个异步iterable(generator or not),并在多个协程中同时迭代所有这些异步iterable。每个协同程序将结果放入
asyncio.Queue
,然后由客户端代码迭代:迭代器代码:
示例客户代码:
^{pr2}$输出:
注:上面的代码使用^{} 第三方库。} 库与上面的代码相同,而且更多。在
PS2:^{
这是普通同步发电机。您可以在其中使用
requests
,但如果您想使用异步aiohttp
,则需要使用async def
定义{a1}。在在多个异步生成器上迭代会更有趣。不能使用普通的
zip
,因为它与普通iterable一起工作,而不是异步iterable。因此,您应该实现自己的(这也将支持并发迭代)。在我做了一个小原型,我想它能满足你的需要:
^{pr2}$输出:
时间显示不同的搜索同时运行。在
相关问题 更多 >
编程相关推荐