2016-09-16 15 views
2

私はファイバーが協調スレッドであることを知っています。ファイバーは実行コンテキストを制御しますが、プリエンプティブ・スレッドは実行コンテキストを制御しません。ファイバが制御を行うことができます。つまり、ファイバは明確に定義された場所で開始および停止できます。ruby​​ファイバープログラムの制御フロー

明らかに、事象が発生したルビーにおいて繊維が使用される理由は、反応器パターンによって引き起こされるネストされたブロックを清掃することである。

しかし、ファイバを使用する以下のスクリプトの制御フローを把握しようとするのは難しいです。

def http_get(url) 
    f = Fiber.current 
    http = EventMachine::HttpRequest.new(url).get 

    # resume fiber once http call is done 
    http.callback { f.resume(http) } 
    http.errback { f.resume(http) } 

    return Fiber.yield 
end 

EventMachine.run do 
    Fiber.new{ 
    page = http_get('http://www.google.com/') 
    puts "Fetched page: #{page.response_header.status}" 

    if page 
     page = http_get('http://www.google.com/search?q=eventmachine') 
     puts "Fetched page 2: #{page.response_header.status}" 
    end 
    }.resume 
end 

私はそれを理解する方法:

1)EMは、繊維が作成され、その後、履歴書が呼ばれた)

2のイベントループを開始します。 newに渡されたコードブロックがすぐに実行されるか、またはresumeが呼び出された後に実行されますか?

3)http_getが最初に呼び出されます。これは非同期イベントを行います(Linuxではselect、poll、またはepollを使用します)。非同期イベントの(コールバックメソッド内の)イベントハンドラを設定します。次に、ファイバーは自発的にEventMachineがオンになっているスレッド(メインスレッド)に制御権を与えます。ただし、コールバックが呼び出されるとすぐに、f.resume(http)を使用して制御を取り戻します。しかし、この簡単な例では、f.resume(http)の後に私自身のコールバックコードを置くことになっていますか?今のところ、f.resume(http)のように見えるのは、ファイバーに制御権を戻すだけで、何もしません。

降伏後に何が起こるかは、コントロールがイベントループに入るEventMachineに行きます。したがって、2番目のhttp_getはまだ呼び出されていません。いったんコールバックが呼び出されると、コントロールはファイバーに戻されます(私たちは1つのファイバーを使用します。ニューです。だから、この中に1つのファイバー・インスタンスしかないと仮定します)。しかし、いつ2番目のhttp_getが呼び出されますか?

+0

自分自身への注意:ファイバーを作成すると、ファイバーは自動的には実行されません。むしろ、Fiber#resumeメソッドを使用して明示的に実行する必要があります。 – Donato

答えて

0

私はあなたのためにそれに答えることができるかどうかを見てみましょう。 14行目かどうかをチェック:

01: def http_get(url) 
02: f = Fiber.current 
03: http = EventMachine::HttpRequest.new(url).get 
04: 
05: # resume fiber once http call is done 
06: http.callback { f.resume(http) } 
07: http.errback { f.resume(http) } 
08: 
09: return Fiber.yield 
10: end 
11: 
12: EventMachine.run do 
13: Fiber.new{ 
14:  page = http_get('http://www.google.com/') 
15:  puts "Fetched page: #{page.response_header.status}" 
16: 
17:  if page 
18:  page = http_get('http://www.google.com/search?q=eventmachine') 
19:  puts "Fetched page 2: #{page.response_header.status}" 
20:  end 
21: }.resume 
22: end 
  1. ライン21は、コード行である14-20
  2. ファイバコードは思わ以下を実行するファイバーの実行を開始:私は説明を支援するために行番号を追加しています我々はgoogle.comeでGETをすることができます。 17行目でhttp_getから有効な応答があるかどうかを確認し、18行目で次の要求を実行して文字列eventmachineを検索します。
  3. ライン21で.resumeによってファイバの実行が開始されると、ライン14が実行され、http_getメソッドが呼び出されます。
  4. 02~07行は、非同期HTTP GET要求とコールバックを設定します。
  5. 行09は、EventMachineに制御を戻します。
  6. 03行目からの非同期HTTP GET呼び出しが非同期的に実行され、06行目または07行目のコールバックのいずれかが発生すると、13行目から20行目に作成された元のファイバーがそのコントロールを返します。
  7. ファイバー実行が15行目から再開しました。06/07行のコールバックがhttpオブジェクトへの参照を渡しました。これは14行目の変数pageで参照され、続いて15行目でHTTP要求ステータスをダンプします。
  8. ファイバーがさらに実行を続けると、pageが真実値であるかどうかがチェックされ、次にhttp_getが新しいURLで呼び出されます。コードif pageは、nilのチェックなしでpageにアクセスした場合、15行目が爆破されたため、nilの場合には実行されません。
  9. 同様のプロセスの繰り返し - 02行目から07行目はHTTP GET呼び出しを設定し、9行目はEventMachineに制御を戻します。
  10. しばらくすると、コールバックの1つが呼び出され、ファイバリカバリ制御としてライン19が実行されます。
  11. 19行目の実行後、ファイバーが死んでしまいます。

希望を明確にします。

追加のロジックでHTTP GETの応答を処理する限り、putsをいくつかの意味のある処理ロジックに置き換えることができます。このサンプルのputsは応答を扱っているようで、コールバックは主にファイバを再開するために使用されます。