I like Ruby too.

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:慣れてくるとこれしなくてもうまく書けるので、自分は使ってません

2016-05-01 toRubyイベントの設計と実装

toRubyイベントの設計と実装 - toteka04編 15:02  toRubyイベントの設計と実装 - toteka04編を含むブックマーク  toRubyイベントの設計と実装 - toteka04編のブックマークコメント

この記事は、とちぎRuby勉強会が主催するイベントの設計と実装についてのメモです。

おもに直近に行われたtoteka04について述べます。

自分の立場

最初は、私のそばの人たちに、日本中のすごい人たちと同じ時間、同じ場所を、与える係でした。

いまは、来てくれる人みんなに、与える係です。

設計の指針

遠くに住んでいるみなさんをとちぎにお招きし、会話を楽しむことができたらいいなあ。

トークする側と聞く側、という関係だけではなく、参加者・スタッフ全員が対話する関係を築きたいと考えています。

コンセプトは「サロン」です。

指針、価値、toRubyイベントのらしさを表現するものとしてサロンという言葉を認識したのはtoteka03でした。

プラクティスの良し悪しは「サロンぽさ」が根拠になります。

テーブルなし

講演者と参加者の距離をできるだけ近づけるため、参加者の前にテーブルを置きません。多少不便があると思いますが、がまんしてね。

今回は席間の移動を考え、イスとイスの間の空間をすこし多めにしました。

猫廼舎さんのコーヒーを提供したとちぎRuby会議06では、テーブルをイスの前ではなく横に配置しました。これも講演者と参加者の前にモノを置かないためのプラクティスです。

荷物置きテーブル

テーブルなし」にしたため、手荷物を置くためのテーブルを壁際に用意しました。荷物置きテーブルはイスはありません。


PCへの配慮

テーブルなし」とも関連しますが、PCを利用する人への支援は手薄になっています。今回は主に講演準備の方のための電源を少し用意しました。

ツダるより、対話を!というほど強い意図はありませんが、参加者の皆さんには不便があったと思います。ごめんなさい。


お菓子(おみやげ)置き場と飲み物

毎回、たくさんのお土産をいただいています。ありがとうございます。

飲み物とお土産のためのスペースを後方に準備します。休憩時間の対話を促せるのではないかと期待しています。

ゴミ袋も一緒に置きます。

飲み物用の紙コップと、紙コップに名前を書くためのペンを一緒に用意しています。名前を書いてもらうことで、紙コップの紛失を防ぎます。


タイマーシステム

とてか01でプログラムの時間を守れなかった反省から、積極的なタイムキープをみんなで行います。

プログラムごとの残り時間を表示し、残りが0秒になったら全員で拍手します。

これは招待講演中であれ、質疑応答中であれ、どのような状況でも行われ、そこで強制終了となります。LTの銅鑼の気持ちいいやつですね。

タイマーシステムの紹介と拍手の練習を開会時に行います。


前座イベント

参加者のみなさんの声出しの練習として、前座イベントを行います。(toteka03, 04では293本の朗読会


会場設営の時間にはブレがあり、受付、開演までの時間がまちまちなので時間調整にも使えます。(余裕を持っているのでたいてい早い)

もちろん、プロジェクタやマイク、照明などの確認もできます。


書籍プレゼント

最初のとちぎRuby会議に参加していたツテで、オライリー様、オーム社様に毎度プレゼント書籍を提供していただいてます。ありがとうございます。

今回のtoteka04では翔泳社様も提供いただきました。

(いつも @ さんにお願いするの忘れちゃう)

プレゼントを配るタイミングで参加者の皆さんからひとこともらったり、スタッフと会話をしたり、書籍プレゼントも会話を促すために利用します。


移動できるパーティー

懇親会などのパーティーは、ビュッフェスタイルにして歩き回れるようにします。

ビュッフェスタイルは自然といろんな人とすれ違うのでおすすめです。

また、早く食べ終わってしまったり、講演を聞いて昂ぶってしまった人がスライドを使って講演できるようにしてあります。


全員発言

いつもできるだけ多くの人に発言してもらいたいと思っています。toteka04では初めての試みとして、全員からコメントをもらうようにしました。

人数が多く、時間が見積もれないため、スライドを利用して話す人とスライドなしで話す人の順序を工夫して、スライド接続中にコメントをもらうようにしました。


パネル

パネラーの意見をメモする会、ではなく、全員がパネラーのように考える時間を作りたいと思いました。チョットデキルパネルに関してはmiwa719がいつか説明します。

パネル内もお題ごとに時間を区切り、ひとつのネタに集中しないようにしました。

また、最初に全てのお題をスライドに表示して、ほんの少し考える時間を増やしました。

つづく

まだいっぱいあるような気がするけど、今日はここまで

2016-04-24 とちぎテストの会議情報suzuri

咳が提供した製品は金で買える! 14:41 咳が提供した製品は金で買える!を含むブックマーク 咳が提供した製品は金で買える!のブックマークコメント

suzuriで売ってる六つ娘ノートを提供したよ!(まだ世界にひとつしかない)

みんなも金で買おう!

咳 ( m_seki ) の【しかえしブルー6】ノート ∞ SUZURI(スズリ)

2016-04-22 とちぎテストの会議04情報Extended

とてか書籍プレゼント翔泳社10:52  とてか書籍プレゼント翔泳社編 を含むブックマーク  とてか書籍プレゼント翔泳社編 のブックマークコメント

こんどは翔泳社さまから頂いたプレゼントの紹介です。

著者の方も参加されるのでサインをねだろう!

現場で使えるソフトウェアテスト Java編

現場で使えるソフトウェアテスト Java編

著者の町田さんが参加されます!

椎葉さんがDDD面白いって言ってたのでリクエストした!

川口さんがこれを使ったワークショップやってたよ! http://d.hatena.ne.jp/m_seki/20131110

スターティングGo言語 (CodeZine BOOKS)

スターティングGo言語 (CodeZine BOOKS)

自分がほしいやつ!