compassが遅い件 vol.3

0 件のコメント
「compassが遅い件 vol.2」の続きです。

今回はcssの生成を並列化したいと思います。
ディレクトリ構成等々は、vol.1・vol.2と同様です。

またもやconfig.rbに処理を書き込むカタチになります。

※ vol.1に記載した↓とは別件です。
> 最終的には、このグループでのコンパイルをforkさせ、複数のグループを並列にコンパイルさせるとこまでやりました。
> 今回は、それをするための前準備になります。

必要なものをインストールする

今回は並列実行ということで、Parallelというgemを使いたいと思います。
(スレッド数の管理もしてくれるし、とても楽に導入できたので。)

・Parallelをインストール(筆者はMacです…)
$ sudo gem install parallel
・Compassのバージョン
$ compass -v
Compass 0.12.2 (Alnilam)
Copyright (c) 2008-2014 Chris Eppstein
Released under the MIT License.
Compass is charityware.
Please make a tax deductable donation for a worthy cause: http://umdf.org/compass

並列化が実感できる環境をつくる

「vol.2」で作成したsass/test.scssはコンパイルに10秒以上かかっていたので、test2.scssとtest3.scssをつくり、css生成がブロックされる状態にしておく。
$ cp -ip sass/print.scss sass/test2.scss
$ cp -ip sass/print.scss sass/test3.scss
準備オッケー。
通常のコンパイルをしてみる。
$ compass compile --time --force
identical stylesheets/ie.css (0.0s)
identical stylesheets/print.css (0.0s)
identical stylesheets/screen.css (0.03s)
identical stylesheets/test.css (18.165s)
identical stylesheets/test2.css (0.001s)
identical stylesheets/test3.css (0.0s)
Compilation took 18.201s
test.css生成に時間がかかり、test2.cssとtest3.cssの生成がブロックされているのが分かります。

ソースの修正

修正箇所は、sass_filesのループで回してるところをparallelを使って並列化させるだけ。

ここの処理を_config.rbで上書きし、並列化させる。
require 'parallel'
module ::Compass
class Compiler
def run
failure_count = 0
if new_config?
# Wipe out the cache and force compilation if the configuration has changed.
remove options[:cache_location] if options[:cache_location]
options[:force] = true
end
# Make sure the target directories exist
target_directories.each {|dir| directory dir}
# Compile each sass file.
result = timed do
Parallel.each(sass_files.zip(css_files), :in_threads => 2) do |sass_filename, css_filename|
begin
compile_if_required sass_filename, css_filename
rescue Sass::SyntaxError => e
failure_count += 1
handle_exception(sass_filename, css_filename, e)
end
end
end
if options[:time]
puts "Compilation took #{(result.__duration * 1000).round / 1000.0}s"
end
return failure_count
end
end
end
view raw _config.rb hosted with ❤ by GitHub

すると、上限2スレッドでcss生成が開始される。
(test.cssでブロック中にtest2.css、test3.cssが生成されてるのがわかる。
$ compass compile --time --force
identical stylesheets/ie.css (0.001s)
identical stylesheets/print.css (0.001s)
identical stylesheets/screen.css (0.016s)
identical stylesheets/test2.css (0.001s)
identical stylesheets/test3.css (0.001s)
identical stylesheets/test.css (16.213s)
Compilation took 16.216s

オプションで指定できるようにする

例のごとく、環境変数でパラメータを受け取れるようにします。
今回は、全ソース乗っけます。(いろいろ細かく書いていってたので、まとめの意味で。
### コンパイル対象を絞り込みするオプション
# 指定がない場合のコンパイル対象
DEFAULT_TARGET_PATTERN = ""
# 値にマッチするscssファイルをコンパイル対象として絞り込む
SASS_FILE_PATTERNS = {
"IE" => "^.*ie.*$",
"PRINT" => "^.*print.*$",
}
TARGET_PATTERN = ENV['TARGET_PATTERN'] || DEFAULT_TARGET_PATTERN
# 画像生成のサイズをメモリにキャッシュさせる
DEFAULT_DIMENSIONS_CACHE = false
if ENV['DIMENSIONS_CACHE'] === "true"
DIMENSIONS_CACHE = true
elsif ENV['DIMENSIONS_CACHE'] === "false"
DIMENSIONS_CACHE = false
else
DIMENSIONS_CACHE = DEFAULT_DIMENSIONS_CACHE
end
# cssファイル生成のスレッド数
MAX_COMPILE_THREADS = 2 #上限値(超えたら並列生成しない
DEFAULT_COMPILE_THREADS = 1
COMPILE_THREADS = ENV['COMPILE_THREADS'] && ENV['COMPILE_THREADS'].to_i || DEFAULT_COMPILE_THREADS
### コンパイル対象を絞り込む対応
module ::Compass
class Compiler
def sass_files(options = {})
exclude_partials = options.fetch(:exclude_partials, true)
opt_sass_files = self.options[:sass_files]
# ファイル指定あり
if opt_sass_files
return opt_sass_files
end
# ファイル指定なし
sass_files = Dir.glob(separate("#{from}/**/#{'[^_]' if exclude_partials}*.s[ac]ss"))
##### 取得したsass_filesを操作することで、コンパイル対象を変更することができる
target_pattern = SASS_FILE_PATTERNS[TARGET_PATTERN]
# 指定がないので絞り込ままい
if target_pattern.nil? || target_pattern.empty?
return sass_files
end
# 指定があるので正規表現で絞り込み
target_regexp = Regexp.new(target_pattern)
_sass_files = []
sass_files.each do |file|
_file = File.basename(file)
if target_regexp =~ _file
_sass_files.push(file)
end
end
return _sass_files
#####
end
end
end
### image-width/image-heightの高速化
if DIMENSIONS_CACHE
module ::Compass::SassExtensions::Functions::ImageSize
@@dimensions_cached = {}
def image_dimensions(image_file)
if @@dimensions_cached[image_file.value].nil?
options[:compass] ||= {}
options[:compass][:image_dimensions] ||= {}
options[:compass][:image_dimensions][image_file.value] = ImageProperties.new(image_path_for_size(image_file.value)).size
@@dimensions_cached[image_file.value] = options[:compass][:image_dimensions][image_file.value]
end
@@dimensions_cached[image_file.value]
end
end
end
### cssファイル生成を並列化
if MAX_COMPILE_THREADS >= COMPILE_THREADS && COMPILE_THREADS > 1
require 'parallel'
module ::Compass
class Compiler
def run
failure_count = 0
if new_config?
# Wipe out the cache and force compilation if the configuration has changed.
remove options[:cache_location] if options[:cache_location]
options[:force] = true
end
# Make sure the target directories exist
target_directories.each {|dir| directory dir}
# Compile each sass file.
result = timed do
Parallel.each(sass_files.zip(css_files), :in_threads => COMPILE_THREADS) do |sass_filename, css_filename|
begin
compile_if_required sass_filename, css_filename
rescue Sass::SyntaxError => e
failure_count += 1
handle_exception(sass_filename, css_filename, e)
end
end
end
if options[:time]
puts "Compilation took #{(result.__duration * 1000).round / 1000.0}s"
end
return failure_count
end
end
end
end
view raw _config.rb hosted with ❤ by GitHub
#!/usr/bin/ruby
command_options = ARGV
# config.rbに渡すパラメータを定義
# 'key' => { // zoocompassで処理を分岐する場合に使うキー
# 'env' => '', // config.rbで使う環境変数名
# 'opt' => '', // zoocompass実行時に指定するオプション名
# }
#
custom_options = {
'compile_target' => {
'env' => 'TARGET_PATTERN',
'opt' => '--target',
},
'dimensions_cache' => {
'env' => 'DIMENSIONS_CACHE',
'opt' => '--enable-dimensions',
},
'compile_threads' => {
'env' => 'COMPILE_THREADS',
'opt' => '--compile-threads',
}
}
# custom_optionsのオプションを指定していた場合は、オプションから削除+環境変数へセットする
custom_options.each do |o,v|
index = command_options.index(v['opt'])
if !index.nil?
# 環境変数へセット
option = command_options.values_at(index + 1)[0]
ENV[v['env']] = option
# オプションから削除
command_options.delete_at(index + 1)
command_options.delete_at(index)
end
end
# compassを実行する
compass_options = command_options.join(' ')
compass_command = 'compass ' + compass_options
system(compass_command)
view raw zoocompass hosted with ❤ by GitHub

下記のようなコマンドで実行できます。
$ ./bin/zoocompass compile --time --force --compile-threads 2

終わりに

だいぶ複雑になってきましたね。。
苦肉の策でもあるので、ほんとにどうしようもないときに。。とか使いどきを選んでいただきたい所存。

以上!

0 件のコメント :

コメントを投稿