[ruby-list:49633] Re: IO.popen の不審な挙動を再現するサンプルコード

From: 尾川敏也 <ogw@...>
Date: 2013-10-06 01:53:23 UTC
List: ruby-list #49633
尾川です。

Tanaka Akira <akr@fsij.org> wrote:
> `close_write': closed stream (IOError) というのは出なかったようですから、
> その点は直ったのではないかと思います。

はい、そうでした。

昨夜、再度最新の r43149 を svn co して Windows XP と Ubuntu 12.04 の
両方で試しました。ruby -v の結果は

    Ubuntu:  ruby 2.1.0dev (2013-10-05 trunk 43149) [i686-linux]
    Windows: ruby 2.1.0dev (2013-10-05) [i386-mswin32_100]

です。

先の test.rb の中のパイプ使ったメソッドチェーンをそれぞれの OS で合
計数万回実行させましたが、どちらの OS でも Ruby 自身からのエラーメ
ッセージは全く表示されず、テストスクリプトを最後まで実行できました。

ですので、`close_write': closed stream (IOError) の件は解決している
ようです。


> >         external: too less field (3 for 6) at line 2784
> このメッセージは手元の環境では出ないのでわかりませんが、なんなんですかねぇ。
> (手元の環境は Debian GNU/Linux 7.1 (wheezy) です。)

元々私の手元の環境でも、Linux の上では殆ど全く問題が出ていませんで
した。

昨夜の実験でも、Ubuntu では全く発生しませんでした。(Windows では、
これまでどおり平均すると十数回に一回程度で発生していました。)

Ubuntu 上で唯一経験した問題は、[ruby-list:49611] で報告した
ruby 2.0.0-p247 での `close_write': closed stream (IOError) の件だ
けです。

思い返すと、Ubuntu では too less field のメッセージは一度も見ていな
いような気もします。(もっとも、Ubuntu でのテストは最初に報告した時
と昨夜の実験だけで、他は殆ど Windows でしかテストしていないのですが。)

何とか Ubuntu でも再現できないかと考えて、昨夜の実験でも少し試しま
したが、上述のとおり、やはり再現しませんでした。

試した内容は、具体的には以下のとおりです。

Windows の経験では、テストデータの行数や外部コマンドが書き出すフィー
ルド数を少し変えると、現象が発生する頻度がガラリと変わったことがあ
りました。

そこで、test.rb の中でパラメータの組み合わせを変更して繰り返すよう、
以下のように変更にして、

    ruby test.rb 2>&1 | tee log.txt

しました。

その結果を今朝確認したのですが、Ruby からはもちろん、外部コマンドか
らもエラーメッセージは皆無で、全て正常に実行できているようでした。

# ---------------------------------------------------------
require_relative        "use_iopopen"   # IO.popen

cycle = 1000

[3, 4, 5, 6, 7, 8, 9, 10, 20].each do |nout|
  [2000, 3000, 4000, 5000].each do |nline|

    puts "@@@@@ nout=#{nout}  nline=#{nline} @@@@@"

    cmd = "./external #{nout}"  # C 版: nout フィールドを出力

    # テスト用データの生成
    elem = "123456789ABC\t"             # 1 要素
    line = elem * 30                    # 1 行中の要素数
    line.sub!(/\t$/, "\n")
    data = line * nline                 # 総行数 nline

    # pipe を使ったメソッドチェーンを cycle 回繰り返し実行
    n = 0
    cycle.times do
      n += 1
      puts "----------- #{n} / #{cycle} ---------"
      data.|(cmd).|(cmd)
    end

  end
end
# ---------------------------------------------------------


何はともあれ、Windows と Linux で現象が違うのは確かな事実なので、何
かが違うはずなのですが、私の想像力では、次の3つの可能性くらいしか
思いつきません。

(1) OS 側の pipe システムコールの振る舞いに何か違いがある。

    ただ、IO.popen ではなく Open3.pipeline_rw を使えば Windows でも
    現象は出ないので、可能性は低いかもしれないです。

(2) IO.popen に関係した部分で、Linux 用と Windows 用では違うコード
    を実行していて、その Windows 側に何かがある。

    私の力では Ruby のソースコードはとても追えないので、違う部分を
    実行しているのかどうか実際に確かめた訳ではないのですが。

(3) 私の手元のマシンのスペックが Windows と Ubuntu で異なり、タイミ
    ングに起因する現象が起きやすかったり起きにくかったりしている。

    ちなみに、PC 購入時の取扱説明書を確認したところ、主なスペックは
    以下のようでした。

        Windows: Intel Core2 Duo E6300 1.86 GHz メモリ 2 GB
        Ubuntu:  Intel Core2 Duo E7400 2.8  GHz メモリ 4 GB

    Ruby をビルドしている時の体感で言うと、Ubuntu の方が2倍くらい
    速いです。


以上、長文で失礼しました。

-- 
尾川敏也 ogw@shizuokanet.ne.jp
http://www6.shizuokanet.ne.jp/ogw/

In This Thread