S3に画像をアップロードするためにペーパークリップを使用しています。しかし、このアップロードは非常に遅いことに気付きました。送信が完了する前に、ファイルがサーバーを通過し、処理されて S3 サーバーに送信される必要があるためだと思います。
これを加速する方法はありますか?
ありがとう
S3に画像をアップロードするためにペーパークリップを使用しています。しかし、このアップロードは非常に遅いことに気付きました。送信が完了する前に、ファイルがサーバーを通過し、処理されて S3 サーバーに送信される必要があるためだと思います。
これを加速する方法はありますか?
ありがとう
コードを投稿していないので、ここでいくつかの仮定を立てます。
Album
andImage
モデルがありますAlbum has_many :images
多くの画像をアップロードするために、フォームは次のようになります。
<%= 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_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倍高速です。
高速化するもう 1 つの方法は、Threadsを使用することです。delayed_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
メソッドにこの単純な変更を加え、gem を追加しないことで、以前と同じアップロードが0.017628 秒で実行されます。これはよりも1,313倍高速ですdelayed_paperclip
。また、通常のセットアップよりも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
注:画像の保存をバックグラウンド タスクにプッシュしてからリダイレクトするためです。読み込まれるページにはまだ画像がありません。ユーザーは 、ページを更新 するために更新する必要があります。これを回避する 1 つの方法は、 pollingを使用することです。ポーリングとは、JavaScript が約 5 秒ごとに変更をチェックし、変更があればページに変更を加えることです。
もう 1 つのオプションは、 Web ソケットを使用することです。Rails 5 ができたので、ActionCableを使用できます。画像が作成されるたびに、アルバムの更新をブロードキャストします。ユーザーがそのアルバムのそのページにいる場合、データベースで更新が行われるとすぐに、ユーザーが更新したり、ブラウザが無限ループで 5 秒ごとにリクエストを行ったりしなくても、更新が行われることがわかります。
クール。
アップロードが速くなるように見えるように改善したいですか、それとも実際にアップロードを速くしたいですか?
前者の場合は、delayed_jobなどを使用して、画像処理ロジックをバックグラウンド タスクに入れることができます。このようにして、ユーザーがボタンをクリックすると、画像の処理中にすぐに次のページに移動します (タスクが完了するまで、「処理中」の画像プレースホルダーを表示できます)。
後者の場合は、サーバーとインターネット接続に完全に依存しています. どこでホストしていますか?
S3に直接アップロードするのはどうですか?
ペーパークリップが箱から出してこれを行うかどうかはわかりませんが、それを行うことができます.
http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?UsingHTTPPOST.html
cwninjaが推奨するように、この余分なアップロードを取り除くために、s3に直接アップロードします。このブログ投稿で説明されているプラグインの修正バージョンを使用します。
http://elctech.wpengine.com/2009/02/updates-on-rails-s3-flash-upload-plugin/
複数のファイルのアップロードを処理するように変更されました(フレックスオブジェクトを再回転します)
これがペーパークリップでどれだけうまく機能するかわからないので、attachment_fuを使用しますが、それで動作させるのはそれほど悪くありませんでした。
遅延ジョブを使用します。これが良い例です
。または、フラッシュ アップロードを使用することもできます。
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