【发布时间】:2016-09-04 17:54:50
【问题描述】:
我编写了一个 Python 脚本,旨在通过使用 AWS Boto 3 list_objects() method 来确定所有可用 AWS S3 存储桶的总大小。
逻辑很简单:
- 从每个 S3 存储桶中获取对象的初始列表(在 1000 个对象后自动截断)
- 遍历对象列表中的每个对象,将该对象的大小添加到 total_size 变量中
- 当存储桶仍有其他对象时,检索它们并重复第 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