Python 3.x 如何动态处理大量协同路由返回的值(异步问题)?

Python 3.x 如何动态处理大量协同路由返回的值(异步问题)?,python-3.x,python-asyncio,python-3.7,aiohttp,Python 3.x,Python Asyncio,Python 3.7,Aiohttp,我有一个非常庞大的URL列表,我想刮。起初,我想做这样的事情: async def main(username, password): sem = asyncio.Semaphore(100) async with aiohttp.ClientSession() as session: await login(session, username, password) tasks = [asyncio.create_task(r_search(sem

我有一个非常庞大的URL列表,我想刮。起初,我想做这样的事情:

async def main(username, password):
    sem = asyncio.Semaphore(100)
    async with aiohttp.ClientSession() as session:
        await login(session, username, password)
        tasks = [asyncio.create_task(r_search(sem, session, url)) for url in hugenumberofurls]
        texts = await asyncio.gather(*tasks)
当然,这需要很长时间,我希望实时处理结果(解析+写入文件)。实现这一目标最有效的方法是什么

我是不是应该先打个电话,然后再做:

async def main(username, password):
    async with aiohttp.ClientSession() as session:
        await login(session, username, password)
        sem = asyncio.Semaphore(100)
        for chunk in chunk(hugenumberofurls):
            tasks = [asyncio.create_task(r_search(sem, session, url)) for url in chunk]
            texts = await asyncio.gather(*tasks)
            process(texts)
我认为这可能是浪费时间,因为process()可能需要几秒钟的时间来持续下载URL


我很乐意接受任何建议,asyncio和aiohttp对于新手来说都很难

让我们使用两个模拟操作构建一个工作示例:

随机导入
导入异步
异步def提取(url):
“”“模拟网络请求”“”
等待asyncio.sleep(random.random()/10)
返回int(url.split(“/”[-1])
def进程(块):
“”“模拟CPU密集型任务”“”
全部(范围(1,10**8))
返回和(块)
首先,您需要一种避免阻塞程序其余部分的方法。例如,可以使用a来并行计算:

来自concurrent.futures导入ProcessPoolExecutor
执行器中的异步定义进程(区块,执行器=ProcessPoolExecutor()):
“”“使用进程池执行器并行运行'process'”
loop=asyncio.get\u running\u loop()
返回等待循环。在执行器(执行器、进程、块)中运行
然后,您需要一种方法来同时运行fetch请求,同时限制连接数量并将结果收集到块中。这可以使用and/or来完成,但要正确实现这一点确实很棘手

相反,您可以考虑使用为此目的而设计的库和操作符:

来自aiostream导入流,管道
异步def main():
“”“执行以下操作:
1.同时获取一组URL,限制为100个任务
2.将结果收集成大小为1000的块
3.使用4种不同的过程并行处理块
4.总结结果
"""
URL=[f”http://my.url/{i} “对于范围内的i(10000)]
结果=等待(
stream.iterate(URL)
|map(fetch,ordered=False,task\u limit=100)
|管道块(1000)
|map(进程在执行器中,顺序=False,任务限制=4)
|管
|pipe.print(“[progress-{}]”)
)
打印(f“>总和(范围(10000))={result}”)
运行此程序需要几秒钟。然后,您必须根据您的用例调整连接限制、块大小和进程数量


免责声明:我是项目的维护者。

Aiostream似乎非常方便!如果进程(chunk)正在为chunk中的每个url解析html,那么从fetch(url)使用
async def parse(html)
wait parse(html)
是否应该更简单?如果我想将进程(块)的结果写入一个文件,比如.csv,该怎么办?@LoBellin这实际上取决于您的用例和解析的cpu密集程度。在我的示例中,获取操作大约需要50毫秒,对一个url的处理大约需要1.5毫秒。在这些限制条件下,使用4个进程来运行处理会使程序速度提高一倍。你必须对这些设置进行实验,以找出最适合你的设置,但我绝对建议从最简单的配置开始(即无分块和多处理)。@LoBellin关于文件编写,你可以使用(最好是与执行器一起使用)或库。好的,我要试一试。您知道我是否可以将几个参数传递给pipe.map(fetch,ordered=False,task\u limit=100)?我想重用aiohttp.ClientSession()。非常感谢。像这样使用星图有用吗:
url=[(会话,url)用于hugenumberofurls中的url]result=wait(stream.iterate(url)| pipe.starmap(r|u search,ordered=False,task|limit=100)| pipe.chunks(1000)| pipe.map(process_in_executor,ordered=False,task_limit=4)| pipe.acculate()| pipe.print(“[progress-{}]”)