5

S3に画像をアップロードするためにペーパークリップを使用しています。しかし、このアップロードは非常に遅いことに気付きました。送信が完了する前に、ファイルがサーバーを通過し、処理されて S3 サーバーに送信される必要があるためだと思います。

これを加速する方法はありますか?

ありがとう

4

6 に答える 6

2

コードを投稿していないので、ここでいくつかの仮定を立てます。

  • あなたのプロジェクトにはAlbumandImageモデルがあります
  • アン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

大事なことはこれだけです。このセットアップでは、合計 12 MB の 22 枚の画像をアップロードすると、ローカル サーバーで: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#') をバックグラウンド ジョブに移動します。

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倍高速です。


高速化するもう 1 つの方法は、Threadsを使用することです。delayed_paperclipGemfile と行から削除し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

メソッドにこの単純な変更を加え、gem を追加しないことで、以前と同じアップロードが0.017628 秒で実行されます。これはよりも1,313倍高速ですdelayed_paperclip。また、通常のセットアップよりも2,336倍高速です。


delayed_paperclip AND を使用するとどうなりますThreadsか?

:files=メソッドを変更しないでください。Gemfile でオンdelayed_paperclipに戻し、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

注:画像の保存をバックグラウンド タスクにプッシュしてからリダイレクトするためです。読み込まれるページにはまだ画像がありません。ユーザーは 、ページを更新 するために更新する必要があります。これを回避する 1 つの方法は、 pollingを使用することです。ポーリングとは、JavaScript が約 5 秒ごとに変更をチェックし、変更があればページに変更を加えることです。

もう 1 つのオプションは、 Web ソケットを使用することです。Rails 5 ができたので、ActionCableを使用できます。画像が作成されるたびに、アルバムの更新をブロードキャストします。ユーザーがそのアルバムのそのページにいる場合、データベースで更新が行われるとすぐに、ユーザーが更新したり、ブラウザが無限ループで 5 秒ごとにリクエストを行ったりしなくても、更新が行われることがわかります。

クール。

于 2017-01-26T03:54:47.683 に答える
1

アップロードが速くなるように見えるように改善したいですか、それとも実際にアップロードを速くしたいですか?

前者の場合は、delayed_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/

複数のファイルのアップロードを処理するように変更されました(フレックスオブジェクトを再回転します)

これがペーパークリップでどれだけうまく機能するかわからないので、attachment_fuを使用しますが、それで動作させるのはそれほど悪くありませんでした。

于 2010-01-29T15:57:31.220 に答える
0

遅延ジョブを使用します。これが良い例です
。または、フラッシュ アップロードを使用することもできます。

于 2010-01-29T23:27:49.400 に答える
0

Rails サーバーから作業をオフロードする S3 に直接アップロードするルートにたどり着いた場合は、私のサンプル プロジェクトをチェックしてください。

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 に答える