5

我正在使用回形针在 S3 中上传图像。但我注意到这个上传速度很慢。我认为因为在完成提交之前,文件必须通过我的服务器,被处理并发送到 S3 服务器。

有没有加速这个的方法?

谢谢

4

6 回答 6

2

您没有发布任何代码,所以我将在这里做一些假设:

  • 在您的项目中,您有一个AlbumImage模型
  • 一个Album has_many :images
  • 您已经 使用存储桶和其他所有东西正确设置了回形针aws-sdk
  • 您一次上传多张图片

为了上传许多图像,您的表单将如下所示:

<%= 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

您要求更快地上传许多图像。有几种方法可以做到这一点。使用 作业 将不起作用,因为您无法将图像等复杂数据传递给作业。


改用delayed_pa​​perclip。它将图像样式创建(如thumbnail: '500x500#')移动到后台作业中。

宝石文件

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倍。


另一种加快速度的方法是使用Threadsdelayed_paperclip从 Gemfile 和行中删除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 秒内运行。这比 . 快1,313delayed_paperclip。它也比常规设置快2,336倍。


如果你使用delayed_paperclip AND Threads会发生什么?

不要改变:files=方法。只需delayed_paperclip在您的 Gemfile 中重新打开并添加回该process_in_background :file行。

在我的机器上使用此设置,该方法平均在0.001277秒内运行。那是

  • 13.8倍于Threads
  • 18,120.6倍于delayed_paperclip
  • 比常规设置快32,248.0

请记住,这是在我的机器上,我还没有在生产中测试过。我也在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

注意:由于我们将图像保存推送到后台任务然后重定向。加载的页面上还没有图像。用户必须 刷新 才能更新页面。解决此问题的一种方法是使用 polling。轮询是 JavaScript 每 5 秒左右检查一次是否有任何更改,如果有任何更改,则对页面进行更改。

另一种选择是使用 Web Sockets。现在我们有了 Rails 5,我们可以使用ActionCable了。每次创建图像时,我们都会广播相册的更新。如果用户在该相册的页面上,他们将在数据库上发生更新时立即看到更新发生,而无需用户刷新或浏览器每 5 秒在无限循环中发出请求。

酷的东西。

于 2017-01-26T03:54:47.683 回答
1

您想改善上传速度更快的外观还是实际上使上传速度更快?

如果是前者,您可以使用delay_job之类的东西将图像处理逻辑放入后台任务中。这样,当用户单击按钮时,他们会在您处理图像时立即转到下一页(您可以显示“处理中”图像占位符,直到任务完成)。

如果是后者,则完全取决于您的服务器和互联网连接。你在哪里托管?

于 2010-01-29T14:42:05.910 回答
1

直接上传到 S3 怎么样?

不确定回形针是否开箱即用,但你可以做到。

http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?UsingHTTPPOST.html

于 2010-01-29T14:55:58.050 回答
0

正如 cwninja 建议的那样,我们直接上传到 s3 以摆脱这种额外的上传。我们使用此博客文章中描述的插件的修改版本:

http://elctech.wpengine.com/2009/02/updates-on-rails-s3-flash-upload-plugin/

我们的修改为处理多个文件上传(重写了 flex 对象

不确定这与回形针的效果如何,我们使用 attachment_fu,但让它与它一起工作并不是那么糟糕。

于 2010-01-29T15:57:31.220 回答
0

使用延迟作业,这是一个很好的例子
或者您可以使用 Flash 上传。

于 2010-01-29T23:27:49.400 回答
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

于 2011-05-27T16:21:45.173 回答