繁体   English   中英

如何在 Python 中使用线程来并行化 AWS S3 API 调用?

[英]How can I use threading in Python to parallelize AWS S3 API calls?

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

逻辑很简单:

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

这是相关的代码片段:

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+ 秒。

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

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

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

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

我遇到了类似的问题。

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

所以代替

s3_client = boto3.client('s3')

你需要写

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

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

除此之外,多线程的正常问题也适用。

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

我有一个解决方案,它可能不适用于所有情况,但可以涵盖很多场景。 如果您在子文件夹分层组织,那么对象首只使用机制列表子描述在这个岗位

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

如果密钥分布均匀且分层,则上述解决方案将表现最佳,如果数据组织扁平,则效果最差。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM