Forum: Ruby-dev Fiber ignores ensure clause

Posted by wanabe (_ wanabe) (Guest)
on 2012-08-05 06:06
(Received via mailing list)
Issue #595 has been updated by wanabe (_ wanabe).

File ensure_fiber2.patch added

ワナベと申します。

(1) GC で mark と sweep の間に、mark されていない Fiber を対象に
(2) ruby_cleanup 中に、メインスレッドに所属するすべての Fiber を対象に
(3) 子スレッド終了時(vm->living_threads から外されるとき)、所属するすべての Fiber を対象に
の 3 つのタイミングで、throw/catch により ensure 節を実行するパッチを書きました。

[ruby-dev:41035] で遠藤さんがおっしゃっているような「yield 中の Fiber は GC しない」
という手法もやってみたのですが、test/ruby/test_fiber.rb がとても終わりそうにないことや
Fiber のマーク処理の重さや Fiber 自体のメモリ消費量などにより、断念しました。
そのため上記(1)のように、rb_gc_marked_p() という関数が必要になるなど強引な手段を使っています。

また、以下のようにして速度低下を計ってみました。

require "benchmark"
GC.start
Benchmark.bm(4) do |x|
  tms = Benchmark::Tms.new
  10.times do |i|
    tms += x.report("   #{i}:") do
      30000.times do
        Fiber.new{Fiber.yield}.resume
      end
    end
  end
  puts " sum:#{tms}"
end

素の r36623 :2.980000   3.120000   6.100000 (  6.107164)
パッチ適用後:3.580000   3.480000   7.060000 (  7.061093)

と、無視できない程度に(約 14%)速度低下してしまいました。
とはいえこれ以上の方法は思いつかないのですが、いかがでしょうか。
----------------------------------------
Bug #595: Fiber ignores ensure clause
https://bugs.ruby-lang.org/issues/595#change-28655

Author: ko1 (Koichi Sasada)
Status: Assigned
Priority: Normal
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: 3.0
ruby -v: -


=begin
 Ruby プロセス終了時,Fiber が ensure を無視します.
 これは,前から直そうと思って手がついていなかった問題です.
 10月末までには直そうと思います.結構複雑なので,後回しにしていましました.

 fib = Fiber.new{
   begin
     Fiber.yield :ok
   ensure
     puts "should be print out"
   end
 }
 p fib.resume
=end
Posted by KOSAKI Motohiro (Guest)
on 2012-08-05 12:19
(Received via mailing list)
> $BAG$N(B r36623 $B!'(B2.980000   3.120000   6.100000 (  6.107164)
> $B%Q%C%AE,MQ8e!'(B3.580000   3.480000   7.060000 (  7.061093)
>
> $B$H!"L5;k$G$-$J$$DxEY$K!JLs(B 14%$B!KB.EYDc2<$7$F$7$^$$$^$7$?!#(B
> $B$H$O$$$($3$l0J>e$NJ}K!$O;W$$$D$+$J$$$N$G$9$,!"$$$+$,$G$7$g$&$+!#(B

$B%Q%C%A$O$^$C$?$/8+$F$$$J$$$N$G$9$,!"B.$1$l$P$A$c$s$HF0$+$J$/$F$b$$$$$H$$$&<gD%$O(B
$B0UL#ITL@$J$N$G@-G=H>J,$H$+$9$4$$?t;z$K$J$i$J$1$l$P5$$K$7$F$b$7$g$&$,$J$$$s$8$c$J$$$G$7$g$&$+(B
Posted by SASADA Koichi (Guest)
on 2012-08-20 10:56
(Received via mailing list)
こちら,返事が大変遅くなって済みません.

(2012/08/05 13:05), wanabe (_ wanabe) wrote:
> (1) GC で mark と sweep の間に、mark されていない Fiber を対象に
> (2) ruby_cleanup 中に、メインスレッドに所属するすべての Fiber を対象に
> (3) 子スレッド終了時(vm->living_threads から外されるとき)、所属するすべての Fiber を対象に
> の 3 つのタイミングで、throw/catch により ensure 節を実行するパッチを書きました。
>
> [ruby-dev:41035] で遠藤さんがおっしゃっているような「yield 中の Fiber は GC しない」
> という手法もやってみたのですが、test/ruby/test_fiber.rb がとても終わりそうにないことや
> Fiber のマーク処理の重さや Fiber 自体のメモリ消費量などにより、断念しました。
> そのため上記(1)のように、rb_gc_marked_p() という関数が必要になるなど強引な手段を使っています。

 とりとめもなく3つほど.

 (1) ですが,ファイナライザのように実行するのはどうかと思っておりまし
た.ただ,その場合,ちょっと管理が大変なんですよね.


 あと,throw よりは,

#define eKillSignal INT2FIX(0)
#define eTerminateSignal INT2FIX(1)

この辺がいいのかなぁ,と思っていました.いや,むしろここを thorw にした
ほうが設計は綺麗かもしれませんね....現在のの実装は,絶対 catch 出来な
い,ってのを目指している感じです.


 速度ですが,小崎さんが仰っているように,あまり気にしてもしょうがない,
という気もするのですが,例えば ensure 節でひっかける可能性があるか,とい
うチェックをするのは結構効くのではないかと思っています.

 というのも,殆どの用途はガチで使っているわけじゃないと思うので,ensure
な処理を必要とする Fiber は,実は少ないのではないかと,

 別の案としては,Fiber 生成時に「ensure ちゃんと処理して」フラグを新設
し,ガチで使う人(ensure をきっちり動かして欲しい人)はこれでやってね
(参考: http://bugs.ruby-lang.org/issues/6694),というのはどうだろう,
とか思うんですが,ちょっと手抜きしすぎでしょうか.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.