我正在使用回形针在S3上传图片。 但我注意到这个上传速度非常慢。我认为因为在完成提交之前,文件必须通过我的服务器,然后被处理并发送到S3服务器。
有加速的方法吗?
感谢
答案 0 :(得分:1)
您是希望更快地改善上传的外观还是实际加快上传速度?
如果是前者,您可以使用delayed_job之类的内容将图像处理逻辑放入后台任务中。这样,当用户单击按钮时,他们会在处理图像时立即转到下一页(您可以显示“正在处理”图像占位符,直到任务完成)。
如果是后者,则完全取决于您的服务器和互联网连接。你在哪里托管?
答案 1 :(得分:1)
如何直接上传到S3?
不确定回形针是否开箱即用,但你可以做到。
http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?UsingHTTPPOST.html
答案 2 :(得分:1)
你没有发布任何代码,所以我将在这里做一些假设:
为了上传许多图片,您的表单将如下所示:
<%= form_for @album, html: { multipart: true } do |f| %>
<%= f.file_field :files, accept: 'image/png,image/jpeg,image/gif', multiple: true %>
<%= f.submit %>
<% end %>
您的控制器看起来像这样
class AlbumsController < ApplicationController
def update
@album = Album.find params[:id]
@album.update album_params
redirect_to @album, notice: 'Images saved'
end
def album_params
params.require(:album).permit files: []
end
end
为了使用您需要的相册来操作图像
class Album < ApplicationRecord
has_many :images, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true
def files=(array = [])
array.each do |f|
images.create file: f
end
end
end
您的Image
文件将如下所示
class Image < ApplicationRecord
belongs_to :album
has_attached_file :file, styles: { thumbnail: '500x500#' }, default_url: '/default.jpg'
validates_attachment_content_type :file, content_type: /\Aimage\/.*\Z/
end
这只是重要的事情。使用此设置,上传22张图像,总共12MB,:files=
方法 41.1806895秒在我的本地服务器上平均执行。要检查方法运行的时间,请使用:
def files=(array = [])
start = Time.now
array.each do |f|
images.create file: f
end
p "ELAPSED TIME: #{Time.now - start}"
end
您要求更快地上传许多图片。有几种方法可以做到这一点。运用 jobs 将无法正常工作,因为您无法将图像等复杂数据传递给作业。
请改用delayed_paperclip。它将图像样式创建(如thumbnail: '500x500#'
)移动到后台作业中。
的Gemfile
source 'https://rubygems.org'
ruby '2.3.0'
...
gem 'delayed_paperclip'
...
图片文件
class Image < ApplicationRecord
...
process_in_background :file
end
它加快了:files=
方法。使用此设置进行的上传(22张图像,12MB)与我的机器上的 23.13998 秒相同。那比以前快了 1.77963 。
另一种加快速度的方法是使用Threads。从Gemfile和delayed_paperclip
行中删除process_in_background :file
。更新您的:files=
方法:
def files=(array = [])
threads = []
array.each do |f|
threads << Thread.new do
images.create file: f
end
end
threads.each(&:join)
end
你可以试试这个,但得到一些奇怪的错误,只看到保存了4张图片。您还必须使用Mutex。此外,您不能在线程上使用:join
,因为如果您加入,该方法将等待线程完成运行。
def files=(array = [])
semaphore = Mutex.new
array.each do |f|
Thread.new do
semaphore.synchronize do
images.create file: f
end
end
end
end
通过对方法的简单更改并且没有添加的宝石,与之前相同的上传在 0.017628秒中运行。这比delayed_paperclip
1,313 快。它比常规设置快<2,336 倍。
如果您使用delayed_paperclip
AND Threads
会怎样?
请勿更改:files=
方法。只需在Gemfile中重新启用delayed_paperclip
,然后添加process_in_background :file
行。
在我的机器上进行此设置后,该方法平均以 0.001277 秒运行。那是
Threads
delayed_paperclip
请记住,这是在我的机器上,我没有在生产中测试过。我也是wifi,而不是以太网。所有这些都可以改变结果,但我认为数字不言自明。
更快地上传图片。完成。
更新:请勿使用delayed_paperclip
。它可能导致繁忙的数据库,并且可能无法保存某些图像。我测试过了。我认为只使用线程就足够了。从process_in_background
文件中删除Image
行。此外,这是我的files=
方法的样子:
def files=(array = [])
Thread.new do
begin
array.each { |f| images.create file: f }
ensure
ActiveRecord::Base.connection_pool.release_connection
end
end
end
注意:因为我们将图像保存推送到后台任务然后重定向。加载的页面还没有图像。用户必须 refresh 更新页面。解决这个问题的一种方法是使用 polling。 轮询是指JavaScript每隔5秒左右检查一次更改,并对页面进行更改。
另一种选择是使用 Web Sockets。 现在我们已经有了Rails 5,我们可以使用ActionCable。每次创建图像时,我们都会广播相册的更新。如果用户在该专辑的该页面上,他们将看到更新发生在数据库发生时,而无需用户刷新或浏览器在无限循环中每5秒发出一次请求。
很酷的东西。
答案 3 :(得分:0)
正如cwninja建议的那样,我们直接上传到s3,以便摆脱这个额外的上传。我们使用此博客文章中描述的插件的修改版本:
http://elctech.wpengine.com/2009/02/updates-on-rails-s3-flash-upload-plugin/
我们被修改为处理多个文件上传(重写了flex对象
不确定这与回形针的效果如何,我们使用attachment_fu,但是使用它不是那么糟糕。
答案 4 :(得分:0)
使用延迟工作,这是一个很好的例子here
或者您可以使用Flash上传。
答案 5 :(得分:0)
如果您最终将上传路径直接上传到S3,从而卸载Rails服务器上的工作,请查看我的示例项目:
使用Rails 3,Flash和基于MooTools的FancyUploader直接上传到S3的示例项目:https://github.com/iwasrobbed/Rails3-S3-Uploader-FancyUploader
示例项目使用Rails 3,Flash / Silverlight / GoogleGears / BrowserPlus和基于jQuery的Plupload直接上传到S3:https://github.com/iwasrobbed/Rails3-S3-Uploader-Plupload
顺便说一句,您可以使用Paperclip进行后期处理,使用类似此博客文章描述的内容:
http://www.railstoolkit.com/posts/fancyupload-amazon-s3-uploader-with-paperclip