【问题标题】:How can I use threading in Python to parallelize AWS S3 API calls?如何使用 Python 中的线程来并行化 AWS S3 API 调用?
【发布时间】:2016-09-04 17:54:50
【问题描述】:

我编写了一个 Python 脚本,旨在通过使用 AWS Boto 3 list_objects() method 来确定所有可用 AWS S3 存储桶的总大小。

逻辑很简单:

  1. 从每个 S3 存储桶中获取对象的初始列表(在 1000 个对象后自动截断)
  2. 遍历对象列表中的每个对象,将该对象的大小添加到 total_size 变量中
  3. 当存储桶仍有其他对象时,检索它们并重复第 2 步

下面是相关代码sn-p:

import boto3

s3_client = boto3.client('s3')

# Get all S3 buckets owned by the authenticated sender of the request
buckets = s3_client.list_buckets()

# For each bucket...
for bucket in buckets['Buckets']:
    # Get up to first 1,000 objects in bucket
    bucket_objects = s3_client.list_objects(Bucket=bucket['Name'])

    # Initialize total_size
    total_size = 0

    # Add size of each individual item in bucket to total size
    for obj in bucket_objects['Contents']:
        total_size += obj['Size']

    # Get additional objects from bucket, if more
    while bucket_objects['IsTruncated']:
        # Get next 1,000 objects, starting after final object of current list
        bucket_objects = s3_client.list_objects(
            Bucket=bucket['Name'],
            Marker=bucket_objects['Contents'][-1]['Key'])
        for obj in bucket_objects['Contents']:
            total_size += obj['Size']

    size_in_MB = total_size/1000000.0
    print('Total size of objects in bucket %s: %.2f MB'
        % (bucket['Name'], size_in_MB))

此代码在其中包含少于 5 MB 左右数据的存储桶上运行相对较快,但是当我遇到其中包含 90+ MB 数据的存储桶时,执行时间从毫秒跃升至 20-30+ 秒.

我希望使用threading module 来并行化代码的 I/O 部分(从 S3 获取对象列表),以便线程可以立即添加存储桶中所有对象的总大小检索它们已完成,而不必按顺序进行检索和添加。

我知道 Python 不支持真正的多线程,因为 GIL,只是为了避免得到响应,但我的理解是,由于这是一个 I/O 操作而不是 CPU 密集型操作,所以threading 模块应该能够提高运行时间。

我的问题与我在这里看到的线程实现的几个示例之间的主要区别在于,我没有迭代已知的列表或集合。这里我必须先检索一个对象列表,看看该列表是否被截断,然后根据当前列表中最终对象的键检索下一个对象列表。

谁能解释一下改善这段代码运行时间的方法,或者在这种情况下不可能吗?

【问题讨论】:

  • 使用 aws s3 命​​令,它更快,但不知道为什么,它也是 API 调用:time aws s3api list-objects --bucket <bucket_name> --output json --query "[sum(Contents[].Size), length(Contents[])]"。与s3_client.list_objects相比,快了两倍。
  • 看看这份文件:quora.com/…
  • 感谢@BMW 提供的信息 - 不幸的是,对我来说,CLI 调用似乎只快了 20-25%。让我伤心的桶里有超过 75,000 件物品。理想情况下,我也会坚持使用 Python,尽管了解这一点是有益的!

标签: python multithreading amazon-web-services amazon-s3 concurrency


【解决方案1】:

我遇到了类似的问题。

为每个线程创建一个单独的会话似乎很重要。

所以不是

s3_client = boto3.client('s3')

你需要写

s3_client = boto3.session.Session().client('s3')

否则线程会相互干扰,并出现随机错误。

除了多线程的正常问题之外。

我的项目是将 135,000 个文件上传到 S3 存储桶。到目前为止,我发现使用 8 个线程可以获得最佳性能。否则需要 3.6 小时,需要 1.25 小时。

【讨论】:

  • 我不知道为什么这是零分,这似乎是正确的答案。至少帮助了我!
【解决方案2】:

我有一个解决方案,它可能不适用于所有情况,但可以涵盖很多场景。如果您将对象按层次组织在子文件夹中,则首先使用in this post 描述的机制仅列出子文件夹@

然后使用这些获得的一组前缀将它们提交到一个多处理池(或线程池),每个工作人员将获取特定于一个前缀的所有键,并使用多处理管理器将它们收集到一个共享容器中。这样一来,密钥将被并行获取。

如果键分布均匀且分层,则上述解决方案的性能最佳,而如果数据组织扁平,则性能最差。

【讨论】:

    猜你喜欢
    • 2018-09-14
    • 2020-06-24
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 2019-03-09
    • 2020-05-01
    • 2012-12-24
    • 2014-07-01
    相关资源
    最近更新 更多