1

共有ライブラリ関数 (サード パーティ関数) の FFI を介してラッパーを作成しました。この共有ライブラリは、サーバーとの接続を確立しようとします。接続確立中、サーバーに到達できない場合、サードパーティ機能は 3 分間待機します。これを回避するために、レールの呼び出し中に次のタイムアウトを使用しようとしましたが、残念ながら機能しませんでした。

  1. ネイティブ タイムアウト
  2. システムタイムアウト
  3. ターミネーター

注:ターミネーターを使用すると、それによって作成された追加のプロセスが無効なプロセスになりました。

Ruby Enterprise バージョン 1.8 を使用しています

4

3 に答える 3

2

FFI 経由の呼び出しは、Ruby のスケジューラを完全にブロックし、スレッド化を許可しないようです。これは、Ruby のグリーン スレッドに関連している可能性があります。

以下の例は、FFI を使用した場合の Ruby の同時実行の動作を示しています。

require 'ffi'

module Sleep
  extend FFI::Library

  ffi_lib FFI::Library::LIBC

  attach_function :sleep, [:uint], :void
end

thread = Thread.start do  
  count = 1 
  while count <= 10
    puts count
    count += 1
    sleep 0.5 
  end 
end

puts "FFI sleep"
Sleep.sleep 5  # Everything blocks, second thread is run after sleep

puts "Ruby sleep"
sleep 5 # Scheduling works, other thread runs simultaneously

thread.join if thread.alive?

これを克服する 1 つの方法は、別のプロセスを fork して FFI 呼び出しを実行し、代わりにタイムアウトを設定することです。

require 'ffi'
require 'timeout'

module Sleep
  extend FFI::Library

  ffi_lib FFI::Library::LIBC

  attach_function :sleep, [:uint], :void
end

child_pid = Process.fork do
  Signal.trap("INT") do
    exit
  end 

  Sleep.sleep 5
  exit
end

begin
  Timeout::timeout(2) do
    Process.wait(child_pid)
  end 
rescue Timeout::Error
  Process.kill("INT", child_pid)
end

フォークされた子プロセスではINT、タイムアウトに達した場合に穏やかにシャットダウンするための信号をリッスンし、もちろん FFI 呼び出しを実行することに関心があります。

親プロセスでは、子プロセスをタイムアウトして、時間内に終了しない限り強制終了するだけです。

于 2011-03-12T14:38:03.270 に答える
1

少しきれい:

require 'ffi'

module Sleep
  extend FFI::Library

  ffi_lib FFI::Library::LIBC

  attach_function :sleep, [:uint], :void, :blocking => true
end
于 2012-01-12T22:38:08.993 に答える
0

C ライブラリでブロックする関数を「ブロッキング」関数としてマークすることができ、FFI はそれらの関数の呼び出しの周りで GIL のロックを解除します。(ffi-1.0.x が必要です)。

例えば

require 'ffi'
module Sleep
  extend FFI::Library

  ffi_lib FFI::Library::LIBC

  # Tell FFI that this function may block
  @blocking = true
  attach_function :sleep, [:uint], :void
end

@blocking はスティッキーではありません。ブロッキングとしてマークしたいすべての「attach_function」呼び出しの前に設定する必要があります。

そして、100%確実な解決策ではありません。ネイティブ コードでブロックされている関数への割り込みは、割り込み可能な関数 (スリープ、読み取り、書き込みなど) では機能しますが、一部のネイティブ コード (CPU を集中的に使用する計算など、他の多くのタイプも同様) では機能しません。

注意: ruby​​ 1.8.x では、ブロッキング関数呼び出しは非常に遅い (1.9 または JRuby でのブロッキング呼び出しと比較して)。

于 2011-03-15T00:12:39.077 に答える