0

単一のプロセス (P1) から出力を取得し、他のプロセス (P2 および P3) を使用して並列タスクを実行しようとしています。ここまでは至ってシンプル。

これを行うには、P2 と P3 を P1 の単一の出力ポートに接続します。私の考えでは、これは、P2 と P3 の両方が同時に並行して取得するパケットを、P1 が出力ポートから送信することを意味するはずです。

私が見つけたのは、P2 と P3 が並行して開始されておらず、代わりに一方のプロセスが他方のプロセスが完了するまで待機することです (または、少なくとも私にはそう思われます)。

たとえば、JSON 入力を受け取り、同時にタイムスタンプを取得して JSON を解析する単純なグラフを次に示します。JSON の解析後に別のタイムスタンプが取得されます。これは、JSON 解析にかかった時間を計算するための基本的な方法として使用されます。

ここに画像の説明を入力

out ポートからの接続の順序に注意してくださいajax/Get(タイムスタンプ接続が最後に追加されました)。

この場合、タイムスタンプの差は約 5 ミリ秒です。これは、NoFlo 以外の環境で JSON 解析にかかる時間とほぼ一致します (実際には、何らかの理由で NoFlo では少し長くなります)。

同じグラフを見てみましょう。ただし、今回はajax/Get出力ポートからの接続順序が変更されています (解析接続が最後に追加されました)。

ここに画像の説明を入力

今回のタイムスタンプの差は約 40 ~ 50 ミリ秒で、これは明らかに大きな差であり、NoFlo の外部での解析よりもはるかに大きくなっています。

誰かが次の点に光を当てることができれば、本当に感謝しています。

  • 接続順によってタイミングがこんなに違うのはなぜですか?
  • からの 2 つの接続ajax/Getがトリガーされ、並行して実行されるようにするにはどうすればよいですか (つまり、相互に待機しません)。

参考になる場合は、FlowHub からのグラフの JSON エクスポートを次に示します。

また、CLI を使用して簡単なグラフを作成し、グラフの流れをよりよく理解して、おそらくこれを引き起こしている原因を明らかにすることができました。

# This executes in the correct order, though likely by
# coincidence and not due to true parallelisation.
#
# Time1 is run and outputted before Time2.
#
Read(filesystem/ReadFile) OUT -> IN Time1(objects/GetCurrentTimestamp)
Read OUT -> IN Parse(strings/ParseJson)

# This executes the entire Parse path before going back to grab
# and output Time1.
#
# Time1 is run and outputted *after* Time2
# Read doesn't send a disconnect message to Parse until *after*
# Time 1 is outputted.
#
# Read doesn't send a disconnect message to Time1 until *after*
# the Parse path has finished disconnecting.
#
# Read(filesystem/ReadFile) OUT -> IN Parse(strings/ParseJson)
# Read OUT -> IN Time1(objects/GetCurrentTimestamp)

Time1 OUT -> IN Display1(core/Output)

Parse OUT -> IN Time2(objects/GetCurrentTimestamp)
Time2 OUT -> IN Display2(core/Output)

'sample.geojson' -> IN Read

to の前に定義されたReadto接続で実行すると、ネットワークは正常に動作しますが、切断を開始する前に他のすべてが完了するまで待機することに気付きました(そうですか?):Time1ReadParseRead

DATA -> ENCODING Read() CONN
DATA -> ENCODING Read() DATA
DATA -> ENCODING Read() DISC
DATA -> IN Read() CONN
DATA -> IN Read() DATA
DATA -> IN Read() DISC
Read() OUT -> IN Time1() CONN
Read() OUT -> IN Time1() < sample.geojson
Read() OUT -> IN Parse() CONN
Read() OUT -> IN Parse() < sample.geojson
Parse() OUT -> IN Time2() CONN
Parse() OUT -> IN Time2() < sample.geojson
Read() OUT -> IN Time1() DATA
Time1() OUT -> IN Display1() CONN
Time1() OUT -> IN Display1() DATA
1422549101639
Read() OUT -> IN Parse() DATA
Parse() OUT -> IN Time2() DATA
Time2() OUT -> IN Display2() CONN
Time2() OUT -> IN Display2() DATA
1422549101647
Read() OUT -> IN Time1() > sample.geojson
Read() OUT -> IN Parse() > sample.geojson
Parse() OUT -> IN Time2() > sample.geojson
Read() OUT -> IN Time1() DISC
Time1() OUT -> IN Display1() DISC
Read() OUT -> IN Parse() DISC
Parse() OUT -> IN Time2() DISC
Time2() OUT -> IN Display2() DISC

ReadtoParse接続が最初に定義されるように順序を切り替えると、すべてがうまくいかず、パス全体が完了するまでTime1パケットが送信されません(実際には今以降です):ReadParseTime1 Time2

DATA -> ENCODING Read() CONN
DATA -> ENCODING Read() DATA
DATA -> ENCODING Read() DISC
DATA -> IN Read() CONN
DATA -> IN Read() DATA
DATA -> IN Read() DISC
Read() OUT -> IN Parse() CONN
Read() OUT -> IN Parse() < sample.geojson
Parse() OUT -> IN Time2() CONN
Parse() OUT -> IN Time2() < sample.geojson
Read() OUT -> IN Time1() CONN
Read() OUT -> IN Time1() < sample.geojson
Read() OUT -> IN Parse() DATA
Parse() OUT -> IN Time2() DATA
Time2() OUT -> IN Display2() CONN
Time2() OUT -> IN Display2() DATA
1422549406952
Read() OUT -> IN Time1() DATA
Time1() OUT -> IN Display1() CONN
Time1() OUT -> IN Display1() DATA
1422549406954
Read() OUT -> IN Parse() > sample.geojson
Parse() OUT -> IN Time2() > sample.geojson
Read() OUT -> IN Time1() > sample.geojson
Read() OUT -> IN Parse() DISC
Parse() OUT -> IN Time2() DISC
Time2() OUT -> IN Display2() DISC
Read() OUT -> IN Time1() DISC
Time1() OUT -> IN Display1() DISC

これが正しい動作である場合、一方が他方をブロックせずに 2 つのブランチを並行して実行するにはどうすればよいですか?

すべてのコンポーネントを非同期にしてみました。その両方を試し、WirePattern を使用して、複数の出力ポートを作成し、それらすべてを一度にデータを送信しようとしました。喜ばしいことではありません - それは常に、最初のエッジが接続される順序に帰着します。ViziCitiesでのNoFloの使用を完全にブロックしているため、これで髪を引っ張っています:(

4

2 に答える 2

0

ブラウザの例は考慮しませんが、バーギーが説明したように、ブラウザ側の JavaScript がどのように機能するかにより、これは確かに深さ優先です。

ただし、noflo-nodejs は EventEmitters を広範囲に使用しているため、CLI の例はより興味深いものです。まだ真の並列ではありませんが、より並行的です。

ここで見られるのは、次の副作用です。

  1. イベントは発生順に処理されます。
  2. グラフでブランチが定義される順序は、イベントが発生する順序に影響します。
  3. ほとんどのコンポーネントは、dataではなくイベントによってトリガーされdisconnectます。disconnect彼らは、結果を処理dataして送信するのを待ちません。

集計では、最初の分岐が 2 番目の分岐の前に実行される理由と、すべてのデータが既に処理された後に切断が続く理由を説明します。

ここでは純粋な同期の印象を与えるかもしれませんが、上記の事実にもかかわらず、システムは依然として並行しています。適切Readな速度で複数のパケットを送信すると、ブランチ 1 とブランチ 2 のイベントが混在していることがわかります。

アップデート:

同期コンポーネントを非同期に変換するための一般的なトリックを次に示します。

setTimeout(function() {
  doTheSyncJob(); // actual code here
  callback();
}, 0);
于 2015-01-30T11:55:13.227 に答える