Вы не опубликовали никакого кода, поэтому я собираюсь сделать несколько предположений здесь:
- в вашем проекте у вас есть
Album
и Image
модель 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 изображений общим объемом 12 МБ занимает :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 изображения, 12 МБ) с этой настройкой, заняла 23.13998 секунд на моей машине.Это в 1.77963 раз быстрее, чем раньше.
Еще один способ ускорить процесс - использовать 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
С этим простым изменением метода и без добавления драгоценных камней,та же загрузка, что и раньше, запускается за 0.017628 секунд .Это в 1079 * 1,313 раз быстрее, чем delayed_paperclip
.Это также * в 1082 * 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 раз быстрее, чем обычные настройки
Помните, это на моей машине, и я не проверял это на производстве.Я также на Wi-Fi, а не Ethernet.Все это может изменить результаты, но я думаю, что цифры говорят сами за себя.
Загрузка изображений быстрее.Готово.
ОБНОВЛЕНИЕ: Не использовать 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
Примечание: Поскольку мы сохраняем изображение, сохраняя его в фоновом режиме, а затем перенаправляем.На загружаемой странице еще не будет изображений.Пользователь должен обновить , чтобы обновить страницу.Одним из способов решения этой проблемы является использование опроса .Опрос - это когда JavaScript проверяет наличие каких-либо изменений каждые 5 секунд или около того и вносит изменения, если таковые имеются, на страницу.
Другой вариант заключается в использовании Web Sockets .Теперь, когда у нас есть Rails 5, мы можем использовать ActionCable .Каждый раз, когда изображение создается, мы транслируем обновление для альбома.Если пользователь находится на этой странице для этого альбома, он увидит, что обновления произойдут, как только они произойдут в базе данных, без обновления пользователя или когда браузер отправляет запрос каждые 5 секунд в бесконечном цикле.
Прикольные вещи.