nya*_*ger 6 amazon-s3 amazon-web-services python-2.7 boto3
我在S3中保存了数以千计的对象.我的要求需要我加载这些对象的子集(在5到~3000之间)并读取每个对象的二进制内容.通过阅读boto3/AWS CLI文档,看起来不可能在一个请求中获取多个对象,所以目前我已将其实现为构造每个对象的键的循环,对象的请求然后读取对象的主体:
for column_key in outstanding_column_keys:
try:
s3_object_key = "%s%s-%s" % (path_prefix, key, column_key)
data_object = self.s3_client.get_object(Bucket=bucket_key, Key=s3_object_key)
metadata_dict = data_object["Metadata"]
metadata_dict["key"] = column_key
metadata_dict["version"] = float(metadata_dict["version"])
metadata_dict["data"] = data_object["Body"].read()
records.append(Record(metadata_dict))
except Exception as exc:
logger.info(exc)
if len(records) < len(column_keys):
raise Exception("Some objects are missing!")
Run Code Online (Sandbox Code Playgroud)
我的问题是,当我尝试获取多个对象(例如5个对象)时,我返回3,有些在我检查是否已加载所有对象时都没有处理.我在自定义异常中处理它.我想出了一个解决方案,将上面的代码片段包装在while循环中,因为我知道我需要的优秀键:
while (len(outstanding_column_keys) > 0) and (load_attempts < 10):
for column_key in outstanding_column_keys:
try:
s3_object_key = "%s%s-%s" % (path_prefix, key, column_key)
data_object = self.s3_client.get_object(Bucket=bucket_key, Key=s3_object_key)
metadata_dict = data_object["Metadata"]
metadata_dict["key"] = column_key
metadata_dict["version"] = float(metadata_dict["version"])
metadata_dict["data"] = data_object["Body"].read()
records.append(Record(metadata_dict))
except Exception as exc:
logger.info(exc)
if len(records) < len(column_keys):
raise Exception("Some objects are missing!")
Run Code Online (Sandbox Code Playgroud)
但是我认为S3确实仍在处理未完成的响应,而while循环会不必要地对S3已经处于返回过程中的对象进行额外请求.
我做了一个单独的调查来验证get_object请求是否同步,它们似乎是:
import boto3
import time
import os
s3_client = boto3.client('s3', aws_access_key_id=os.environ["S3_AWS_ACCESS_KEY_ID"], aws_secret_access_key=os.environ["S3_AWS_SECRET_ACCESS_KEY"])
print "Saving 3000 objects to S3..."
start = time.time()
for x in xrange(3000):
key = "greeting_{}".format(x)
s3_client.put_object(Body="HelloWorld!", Bucket='bucket_name', Key=key)
end = time.time()
print "Done saving 3000 objects to S3 in %s" % (end - start)
print "Sleeping for 20 seconds before trying to load the saved objects..."
time.sleep(20)
print "Loading the saved objects..."
arr = []
start_load = time.time()
for x in xrange(3000):
key = "greeting_{}".format(x)
try:
obj = s3_client.get_object(Bucket='bucket_name', Key=key)
arr.append(obj)
except Exception as exc:
print exc
end_load= time.time()
print "Done loading the saved objects. Found %s objects. Time taken - %s" % (len(arr), end_load - start_load)
Run Code Online (Sandbox Code Playgroud)
我的问题和我需要确认的事情是:
get_object请求确实是同步?如果他们是那么我希望当我在第一个代码片段中检查加载的对象时,应该返回所有这些对象.get_object请求是异步的,那么我该如何处理响应以避免对仍在返回过程中的对象发出额外的S3请求?谢谢!
小智 0
与 Javascript 不同,Python 同步处理请求,除非您执行某种多线程处理(您在上面的代码片段中没有执行此操作)。在 for 循环中,您向 发出请求s3_client.get_object,并且该调用将阻塞,直到返回数据。由于records数组比应有的小,这必定意味着正在抛出一些异常,并且应该将其捕获在 except 块中:
except Exception as exc:
logger.info(exc)
Run Code Online (Sandbox Code Playgroud)
如果没有打印任何内容,可能是因为日志记录配置为忽略 INFO 级别消息。如果您没有看到任何错误,您可以尝试使用 进行打印logger.error。