I like Ruby too.

2016-07-14 dRubyと京都

dRuby京都 19:18 dRubyと京都を含むブックマーク dRubyと京都のブックマークコメント

1999年の7/14にdRubyの最初のバージョンを投稿しました。今年で何歳だろ。

それをきっかけに、翌年のLinux Conference併設Perl/Ruby Conferenceに招待されました。

http://lc.linux.or.jp/lc2000fall/

学会じゃないイベントで話したのはこれがはじめてです。

dRubyのおかげで本を書いたり、いろんなところで話す機会を得たように思います。OSSだけでなく、サラリーマンぽいイベントとか。自分で言うのもおかしいけど、たまにdRubyに感謝しています。

lc2000の会場は京都国際会館。なんと今年のRubyKaigiと同じ会場です。

二度とここにはこないんだろうな、って思っていたので不思議な気持ちです。21世紀初の京都だなー。すごい!!旅費やばい!!

RubyKaigi旅費とスライドスポンサー

例年RubyKaigiのスライドスポンサーを募集しているのですが、今年はまだ当落の発表がないので先行してclass-module/method里親スポンサーを募集しようと思います*1

あなたも一年間、好きな咳プロダクツのクラス/モジュールメソッド里親になって交通費をおごってあげよう!

里親スポンサーの詳細は今週末に。

追記 CFP通りました

(仮題)dRuby in the last century.

追記 里親スポンサー準備した

*1:もちろんunicodeの文字の里親スポンサーの真似です!!https://blog.misosi.ru/2016/04/06/sponsored-sushi-emoji/

2016-07-12 通販でタイヤを買ったちょっと泣ける話

通販でタイヤを買ったちょっと泣ける話 00:51 通販でタイヤを買ったちょっと泣ける話を含むブックマーク 通販でタイヤを買ったちょっと泣ける話のブックマークコメント

いろいろあって通販でタイヤを買いました。

泣ける編

春に東名付近で右リアのエアー警告。ゴルフはABSの回転センサー利用して空気圧の異常を見つけるぽいです。

海老名下りSAでチェックしてもらうとパンクでした。

「高速で帰るしパンク修理不安だなー」と思った(魔が差した)のでリア2本のタイヤ交換することになりました。

「在庫のある銘柄なんですか?」「これしかないです。」

TOYO NANOENERGY3 Plus (トーヨー ナノエナジー3 Plus) 195/65R15 1本

う。TOYOタイヤ。守備範囲外だ..ナノエナジー3plus!? グレード感さっぱりわからない。

「新製品ですよ!16,000円です。2本替えてもらえるなら値引きしますよー」

...

結局工賃込みで35,000円くらいかかりました。とほほ。

オイル交換とか添加剤とか厳しく勧められたけどスルーしました。スタンドめー。

ちょっと泣ける編

前は純正のふつうのタイヤ、後ろはエコタイヤになったんだけど、これがまた乗りにくい。

前だけ転がり抵抗が高いから、惰性で走るときにツンのめる感じ。

燃費はいいんだけど..。

いずれにせよ乗りにくいから4輪同じタイヤにすることを決意しました。

近所で売ってない

近所のタイヤショップは店舗がほぼ倉庫のままなんだけど、とにかく安い。今回もそこで買うつもりで見に行ったんだけど「TOYOタイヤは扱ってないですねー」とのこと。

イエローハットでも取り扱いありませんでした。

じゃあ通販どうなの?

amazonで調べるとSAの半額で売ってるじゃん!泣ける。

ここでディーラーに相談したら持ち込みのタイヤでも交換してくれるとのこと。

楽天も検索したら7000円台のお店があったのでそこで買うことにしました。

ほんとうはディーラーに届くように手配するつもりだったのに自宅に送ってしまった。タイヤはこんな梱包(?)で届きました。

ディーラーでの工賃は2本で5000円。19000円くらいで交換できました。

あーあ。高速で払った金額で4本替えられたよ。とほほ。

ナノエナジー3plus

タイヤはまあまあです。エコタイヤはじめてだけど、ほんとに軽い感じ。走り始めも軽いし、惰性で走ってるときにぜんぜん速度が落ちません。

この感じはロードレーサー(チャリ)乗ってたときの感覚を思い出しました。舵は効くけど手応えが軽いからちょっと不安になるのも似てる。

燃費は(もともといいけど)ちょっとよくなりました。国産タイヤでは最安だし、こだわりのない人にはオススメじゃないかな。

まとめ

  • 通販タイヤ安い!持ち込みで交換してもらえるお店があるなら、オススメ
  • TOYOタイヤ安い!免震ゴムのせい?なんだかよくわからないけど、国産では最安ぽい
  • エコタイヤ軽い!燃費はまあまあ!なれないとちょっと怖いけど
  • 高速道路でタイヤ替えるのはオススメしない

2016-06-12 イスを買った

4000円でイスを買った話 20:36 4000円でイスを買った話を含むブックマーク 4000円でイスを買った話のブックマークコメント

イス合わない

ニトリで買ったイス、もともと合わなかった(試用するときに靴を履いていたせい)んだけど、へたってきたらさらに合わなくなってきました。

小一時間座ってると背中や腰が痛くなってつらいのです。

アーロンチェアとか高そうなの買えば調整しまくれていいのはわかってるんだけど、14万とかそんな資金ないよ。

自分に合うイスを手に入れるにはどうしたらいいんだ。

使ったことあるやつを買おう

職場の素朴なオフィスチェアは数時間座ってても苦にならないのを思い出しました。

なんだよ、ほどほどに合ってるイスしってるじゃん。

というわけで値段調べてみました。


え。

4万もすんの?数千円かと思ってた。

アーロンチェアよりはずっと安いけどさ。

やっぱり庶民ニトリだなーとか、思っていたらオフィス用品の中古があるらしいことを発見。

「オフィスチェア 中古」で探すといくつか出てきました。

職場で座ってるやつの中古を探すと楽天にありました。

手が届きそうだけどちょっと高いなー。

それよりもキズとか汚れを確認できないけど大丈夫だろうか..。

お金払うと思うと急に気になりだしたのです。現物見たいよ..。

物理店舗

世間相場はわかったので、近所のリサイクルショップを見に行きました。

オフィス用品だけあって、同じ型のイスがたくさんあります。そしてみんな汚れ方が違う!

その中から傷みが少ない個体を選んできました。これ通販だったらどうすりゃいいんだろ。

結局買ったのはコレの中古で4,000円。クルマのトランクに積んで持ち帰り。送料無料。


まとめ

  • オフィスチェア、けっこういい。調整幅は少ないけど、日本人向けに作られてるんだから大丈夫なんだよな。
  • 中古の汚れはいろいろ。一品ごとに写真があるところから買った方がいいかも。
  • 最初からこうすればよかった。
  • アーロンチェア買う資金がほしい。

2016-05-22 on_gcつづき

CD-R買ったらほんとにレコード風だった 22:05 CD-R買ったらほんとにレコード風だったを含むブックマーク CD-R買ったらほんとにレコード風だったのブックマークコメント

CD-R買ったの久しぶり。こんな見た目のがあるのねえ。

この厚紙ジャケットも買えばよかった。

on_gcつづき 22:02 on_gcつづきを含むブックマーク on_gcつづきのブックマークコメント

http://d.hatena.ne.jp/m_seki/20160521#1463801531

この改造したやつをコミットしました。どこでも再現性のあるテストは書けなかったので、自動テストが走るファイル名にしませんでした。

2016-05-21 on_gc

どうでもいいような仕事をする 12:32 どうでもいいような仕事をするを含むブックマーク どうでもいいような仕事をするのブックマークコメント

dRubyアプリケーションを雑に作るため、別プロセスに貸しだしたオブジェクトを一定時間、GCから保護するTimerIdConvっていうのがあります。*1

保護するのは簡単なんだけど、保護するのをやめるのがめんどくさい。とりあえずスレッドを使って時々忘れさせるようにしておきました。想定される使い方では、dRubyでサービスを提供するプロセスは終了までそのまま提供するのでそうなってます。

でもできればこういうスレッドなくしてみたい。

で、どうでもいい仕事(この場合は忘れる処理)をするトリガーとしてGC使えないだろうかと考えました。

module OnGC
  module_function
  def on_gc(&blk)
    ObjectSpace.define_finalizer(Object.new, &blk)
  end
end

Object.newしたオブジェクトGCされたとき、ブロックを呼び出すことができます。

def do_gc
  p [:do_GC, Thread.main, Thread.current]
end

OnGC.on_gc { do_gc }
GC.start

puts "end."

実行する。

$ ruby on_gc.rb
end.
[:do_GC, #<Thread:0x007fccf207cd00 dead>, #<Thread:0x007fccf207cd00 dead>]

あれ?そこか。GC二回してみる。

def do_gc
  p [:do_GC, Thread.main, Thread.current]
end

OnGC.on_gc { do_gc }

GC.start
GC.start

puts "end."

end.の前にログがでた。GCがいつ行われるのか、あてにできないってことだよね。

$ ruby on_gc.rb
[:do_GC, #<Thread:0x007fed14080d00 run>, #<Thread:0x007fed14080d00 run>]
end.

ループしてみる

定期的な処理をしたいので、ループさせてみる。

def do_gc
  p [:do_GC, Thread.main, Thread.current]
  OnGC.on_gc { do_gc }
end

と、無限ループしてしまう。プロセスの終わりにGCが走るからじゃなくてファイナライザが働くので無限ループに入ってしまう。

中田さん情報でThread.main.alive?がfalseになるっぽいので終端条件をいれよう。

module OnGC
  module_function
  def on_gc(&blk)
    return unless Thread.main.alive?
    ObjectSpace.define_finalizer(Object.new, &blk)
  end
end

どのスレッドで動くのか

なんとなくGC用のスレッドがあるのかと思ったけど、そうではない。どのスレッドでもGCが発生する可能性がある(と思う)。この実験では明示的なGC.startだけど、いつでも起きるよね。

def do_gc
  p [:do_GC, Thread.current]
  OnGC.on_gc { do_gc }
end

OnGC.on_gc { do_gc }
th = Thread.new do
  10.times do
    GC.start
    sleep(rand)
  end
end

10.times do
  GC.start
  sleep(rand)
end

th.join
puts "end."

できそうにないことを確認する

Threadは作れない?

def do_gc
  p [:do_GC, Thread.current]
  begin
    Thread.new { puts 'helo' }
  rescue
    p $!
  end
  OnGC.on_gc { do_gc }
end

OnGC.on_gc { do_gc }
th = Thread.new do
  10.times do
    GC.start
    sleep(rand)
  end
end

10.times do
  GC.start
  sleep(rand)
end

th.join
puts "end."

なんとつくれた。Thread.main.alive?がfalseのときはThreadErrorになる。

なるほどー。

Thread通信のしかけも動くかな。Queueで試してみる。

require 'thread'
$queue = Queue.new

def do_gc
  p [:do_GC, Thread.current]
  begin
    puts $queue.pop
  rescue
    p $!
    raise($!)
  end
  OnGC.on_gc { do_gc }
end

OnGC.on_gc { do_gc }
th = Thread.new do
  10.times do |n|
    GC.start
    $queue.push(n)
    sleep(rand)
  end
end

10.times do |n|
  GC.start
  sleep(rand)
end

th.join
puts "end."

動く(よびだせる)。でもこう書くと最後にはデッドロックで終わってしまう。だいたいどのスレッドGCが働くかわからないのに、スレッドの待ち合わせするのはだめだよな。その手の操作は別スレッドを作ってやるべきだな。そうする。

def do_gc
  p [:do_GC, Thread.current]
  Thread.new do
    begin
      puts $queue.pop
    rescue
      p $!
      raise($!)
    end
  end
  OnGC.on_gc { do_gc }
end

だいたい定期的な処理

do_gcで時刻を調べて、期限を過ぎていたら特別な処理をするようにすれば定期的な処理が書けそう。

$expires = Time.now + 2

def do_gc
  if $expires < Time.now
    p [:do_gc, Time.now]
    $expires = Time.now + 2
  end
  OnGC.on_gc { do_gc }
end

OnGC.on_gc { do_gc }
th = Thread.new do
  30.times do |n|
    GC.start
    sleep(rand)
  end
end

30.times do |n|
  GC.start
  sleep(rand)
end

th.join
puts "end."

大団円

TimerIdConvのケースでは、こんな風に使おうと思います。

  • keeperスレッドをやめる。(これはすでにやめている)
  • @expiresをon_gcのループの制御に使う。次にrotateする時刻を入れる。nilなら停止。
  • addのケースにだけ、on_gcのループの開始する
      def invoke_keeper
        return if @expires
        @expires = Time.now + @keeping
        on_gc
      end

ループは同時にただ一つだけにしておきたいので、停止中の場合にだけ、開始する。

      def on_gc
        return unless Thread.main.alive?
        return if @expires.nil?
        Thread.new { rotate } if @expires < Time.now
        ObjectSpace.define_finalizer(Object.new) {on_gc}          
      end

まず、プロセス終了中、ループ終了状態をチェックする。次に、rotate時刻を過ぎていたら、別スレッドでrotateする。次回に備えて、on_gcのループの準備をする。ファイナライザーの登録以外、なにも状態を変えないのがミソ。rotateは別スレッドで実行され、状態の変更はsynchronizeの内側で行います。

      def rotate
        synchronize do
          if @expires &.< Time.now
            @gc = @renew      # GCed
            @renew = {}
            @expires = @gc.empty? ? nil : Time.now + @keeping
          end
        end
      end

rotateでは、@expiresを過ぎていたら、GCから保護している箱(Hash)を入れ替え、次のrotateの時刻を設定する。箱がからならnilにして、on_gcのループをやめる。

空になってon_gcのループが終わっても、つぎのaddのときにはinvoke_keeperされて再開される(と期待してる)。commitしていいかなあ。

あわせて読みたい

dRubyによる分散オブジェクトプログラミング

dRubyによる分散オブジェクトプログラミング

The dRuby Book: Distributed and Parallel Computing with Ruby

The dRuby Book: Distributed and Parallel Computing with Ruby

dRubyによる分散・Webプログラミング

dRubyによる分散・Webプログラミング

*1:慣れてくるとこれしなくてもうまく書けるので、自分は使ってません