- http://dlang.org/blog/2017/05/24/faster-command-line-tools-in-d/
- https://nim-lang.org/blog/2017/05/25/faster-command-line-tools-in-nim.html
- https://users.rust-lang.org/t/faster-command-line-tools-in-d-rust/10992/14
こんな感じで巷ではやっているので、crystalはどうだろうと思い試してみた。
# coding: utf-8 # $ crystal build --release fastcmdline.cr # crystal build --release fastcmdline.cr 7.94s user 0.09s system 101% cpu 7.937 total # $ time ./fastcmdline googlebooks-eng-all-1gram-20120701-0 1 2 # max_key: 2006 sum: 22569013 # ./fastcmdline googlebooks-eng-all-1gram-20120701-0 1 2 8.68s user 0.69s system 125% cpu 7.465 total if ARGV.size < 3 puts "synopsis: #{__FILE__} filename keyfield valuefield" exit 1 end filename = ARGV[0] key_field_index = ARGV[1].to_i value_field_index = ARGV[2].to_i max_field_index = [key_field_index, value_field_index].max delim = "\t" # ここで初期値いじってもあんま効果ない・・ 11, 1024 ~ 8192あたりでとったけど11が一番ましくらい sum_by_key = Hash(String, Int64).new(initial_capacity: 11) File.each_line(filename) do |line| # たぶんここでメモリ確保走る分遅い fields = line.split(delim).first(max_field_index + 1) if max_field_index < fields.size key = fields[key_field_index] field_value = fields[value_field_index].to_i64 if sum_by_key[key]?.nil? sum_by_key[key] = field_value else sum_by_key[key] += field_value end end end if sum_by_key.empty? puts "No entries" else max_key = "" max_value = 0.to_i64 sum_by_key.each do |key, value| if value > max_value max_key = key max_value = value end end puts "max_key: #{max_key} sum: #{max_value}" end
同じ環境でdmdやrustとやったところdmdが6.6secs、rustが1.1secsほどなのでcrystalは少し遅い。
アルゴリズム的なところ以外でいうと、
- Hashの初期メモリ確保が小さくて割当なおすので遅い
- splitが毎回メモリ確保するので遅い
- メモリ割り当て時にGCスキャンが走るので遅い
というあたりがありそうなかんじだった。
1.は初期値の11から1024,2048,4096,8192あたりに変えて試したけどとくに効果なし。 2.はちょっとめんどくさいのでやらなかったけど、ここは効果ありそう。 3.はGC.stopが生えていなかったのでパス。
といった形で、まあ結局大して最適化してない。それでもCPythonに比べるとだいぶ速いのですごいなあ。