我的雇主使用Box。它的API非常慢。幸运的是,我们的文件很大程度上是静态的。每晚我可以迭代(递归地) Box文件夹,并将URL存储在本地文件中。在白天使用本地文件可以极大地提高读取和写入Box的脚本的性能。在0级开始递归搜索(爬行器)包括我们不关心的文件夹。所以我们有一个命名的列表,从级别1开始,我想以并行的方式递归搜索它们。
当我观察下面的代码(通过我隐藏的日志/打印语句)时,它似乎没有并行地在起始点下进行搜索。相反,在起点1下搜索整个树,然后在起点2下搜索树,依此类推。
我的问题是:为什么下面的代码不为for storage_dict, starting_point in zip(cache_dict_list, starting_dir_list)中的每一项并发执行爬行器方法
import asyncio
@asyncio.coroutine
def spider(storage_dict, dir_list):
"""Recursive storage of Box information in storage_dict."""
storage_dict = {"key": "value"}
cache_dict_list = [dict() for x in starting_dir_list]
task_list = list()
async def main():
for storage_dict, starting_point in zip(cache_dict_list, starting_dir_list):
task_list.append(asyncio.create_task(spider(storage_dict, [starting_point])))
await asyncio.gather(*task_list)
asyncio.run(main())
total_dict = dict()
total_dict.update([cache_dict.update(x) for x in cache_dict_list])发布于 2021-07-25 13:39:10
原因基本上是异步不是多线程(稍后将对线程进行更多介绍)。Async基本上是对由事件循环执行的任务进行排队。因此,当您执行await asyncio.gather(*task_list)时,您基本上是在说“将所有这些任务放入队列中(Ish),然后等待它们完成。”如果在spider()中使用更多的async和await语句,则可以在队列中对其进行更多拆分,但最终仍将花费大约时间,因为一次只处理队列中的一项。
然后,我们有了threading。这(某种程度上)允许并发。但是,如果资源有限,情况也好不到哪里去,因为cpython使用全局解释器锁(GIL)。GIL意味着基本上单个python进程一次只能使用一个内核,避免了多个内核同时访问和修改数据时可能出现的问题。
但是,如果您想要真正的并发性,则可以使用multiprocessing模块。如何实现这一点可能取决于您希望如何获取和存储数据(以避免导致GIL的多核问题),但基本上它将允许您同时使用多核。
https://stackoverflow.com/questions/68514559
复制相似问题