【发布时间】:2020-02-14 02:35:59
【问题描述】:
我在 Heroku 中运行一个 Django 应用程序,它处理来自用户的多个图像上传并将它们存储到 Amazon S3。问题是这个过程的执行通常需要30s以上(Heroku的时间执行限制)。
我测试了它,需要较长时间的行是将图像文件保存在 ImageField 中的行。这样做是因为必须通过 ProcessImageFile() 裁剪和处理图像。不过这个功能用的时间并不长,而是save方法本身,可能是因为它在保存文件的同时将文件一个一个地存储在S3中。
这是视图(省略不相关的行):
@login_required
def image_create(request):
if request.method == 'POST':
images = request.FILES.getlist("files")
crop_points = json.loads( request.POST.get('crop_points'))
#Validation of inputs in the form: images and other fields
if len(images) < 3 : return JsonResponse({'val_result': 'min_error'})
if len(images) > 12: return JsonResponse({'val_result': 'max_error'})
#We Create the gallery, iterate over the images provided by the form, validate, insert custom fields and save them in bulk associating it to the gallery.
with transaction.atomic():
new_items = []
gallery = Gallery.objects.create( user=request.user )
for i, img_file in enumerate(images):
new_item = Image()
new_item.user = request.user
#-----THIS IS THE PART WHICH TAKES MOST OF THE VIEW PROCESSING TIME: IT IS NOT THE ProcessImageFile FUNCTION, BUT THE SAVE METHOD ITSELF
new_item.image.save( 'img'+ str(i) + '.jpg', content = ProcessImageFile(img_file, crop_points), save=False )
#---------------------------------------------------------------------------------------------------------------------------------------
new_items.append( new_item )
created_objects = Image.objects.bulk_create( new_items )
Belonging.objects.bulk_create( [ Belonging(gallery=gallery, content_id = item.id) for item in new_items] )
for img in created_objects:
img.create_tags(gallery = gallery) #<-We save the notifications for bulk create
return JsonResponse({'status': 'ok', 'gallery': gallery.id})
else:
form = MultiUploadImageForm()
return render(
request,
'upload/create.html',
{'form': form}
)
#I THOUGHT THIS COULD BE THE FUNCTION TAKING TIME BUT IT IS NOT:
def ProcessImageFile(img_file, crop_points):
img = ImageProcessor.open(img_file)
cropped_img = img.crop( ( int(crop_points[0]), int(crop_points[1]), int(crop_points[2]), int(crop_points[3])))
img_io = BytesIO()
cropped_img.save( img_io, format='JPEG', quality=100)
return ContentFile( img_io.getvalue())
我已经尝试使用 Celery 在单独的任务中处理文件上传,但这里的问题是将请求或图像文件传递给任务,因为它们必须被序列化。无论如何,我想这里有一些效率低下的地方,这个简单的视图不应该花费超过 30 秒的时间在 S3 中上传五张图像并返回响应。也许解决方案是将所有图像一起批量发送到 S3,或者以其他方式保存它们,我不知道。
【问题讨论】:
-
您好 - 您将希望将响应返回与文件上传分离。类似于这里的答案之一:stackoverflow.com/questions/670442/… -
-
This 可能会有所帮助。
-
确实可以用 Celery 做到这一点。但尝试发送临时文件名而不是
request或任何不可序列化的文件名。尝试在视图中执行request级别的操作,并将保存文件留给接收临时文件名的 Celery 任务。大多数网络服务器首先将上传的文件保存在一个临时文件中。
标签: python django heroku amazon-s3