3

あなた方の何人かがこれについていくつかの指針を与えることができることを願っています。

Webサービスやデータベースなどのリモートリソースを呼び出す必要があるコードを生成します。

このコードを考えてみましょう

class Parent{    
    IEnumerable<Child> Children;

    int SumChildren() {  
        // note the AsParallel
        return Children.AsParallel().Sum(c => c.RemoteCall()); 
    }   
}

class Child {        
    public int RemoteCall() {
        // call some webservice. I'd like to pool these calls 
        // without having to rewrite the rest of this code
    } 
}

50人の子供に対して、サービスに50回の呼び出しを行い、オーバーヘッドを50回取得します。私の実際の例では、これは簡単に100万回の呼び出しになり、すべてが這うようになります。

私がやりたいのは、呼び出し元のスレッド/タスクに対して透過的な方法でこれらの呼び出しをバッチ処理することです。したがって、サービスを直接呼び出す代わりに、これらの呼び出しをバッチ処理する中央キュー(「鉄道駅」)を呼び出します。

そのため、それを行うと、呼び出し元のタスクがブロックされます。次に、キューはX呼び出しが蓄積されるのを待ってから、要求のリストを使用してリモートサービスに1回呼び出します。

結果が来ると、このキューは戻り値を適切なタスクに返し、ブロックを解除します。呼び出し元のスレッドの場合、これはすべて非表示のままであり、別の関数呼び出しのように見えます。

これはできますか?これを可能にするプリミティブはTPLにありますか?

ちょっとCCRのような匂いがして、他の作業が完了するのを待っていると同時にたくさんのことが起こっています。

もちろん、このコードを書き直して、Parentクラスのリクエストのリストを作成してから、サービスを呼び出すこともできます。問題は、私の本当の問題では、このすべてのコードが生成されるということです。したがって、Child.RemoteCallの実装の「内部を調べる」必要があり、これはすべて、これまでよりもはるかに複雑になります。また、子はリモートオブジェクトなどのプロキシになる可能性があります。実行可能であれば非常に難しいので、この複雑さを分離したいと思います。

これが誰かに意味があることを願っています、そうでなければ私が詳しく説明することを私に知らせてください。

4

3 に答える 3

3

あなたは超並列プログラミングの表面をひっかいています。並行性指向の方法で考える必要があります。バッチに必要な 50 個のジョブではなく、51 個のジョブを開始しています。追加ジョブは、50 個のジョブを管理するジョブです。必要なプリミティブに関しては、必要です。

JOBHANDLE X= GetJobId();
//single job
AddJob(JOBHANLDE X,ChildJob y);
//container of jobs
AddJobs(JOBHANDLE x, ChildJobs Y);

BeginAsyncExecute(JOBHANDLE X);
WaitTillResult(JOBHANDLE X);

ブロッキング プリミティブ (OS カーネルによって提供されるものを超えるもの) を定義し、実行するワーカー スレッドとジョブを管理するエンジンがバックグラウンドで必要です。見た目からすると、これらは PLINQ テクノロジによって処理されます。PLINQ は、優れたグリーン スレッドも使用します。

データベースと Web サーバーが混在するとおっしゃいました。したがって、ジョブ プロセス/関数は、バッチが実行される前に、子を正しいリソースにマップする必要があります。したがって、50 個の子は、はるかに少ないバッチ可能な RPC 呼び出しに削減される可能性があります。

したがって、ジョブ バッチを構築してから、それをブロックします。

より具体的にするのは難しいでしょう。しかし、これまでの議論を踏まえて、あなたが抱えている問題を教えてください。

于 2009-12-14T16:46:54.230 に答える
1

その場合、呼び出し元のタスクがブロックされます。次に、キューは X 回の呼び出しが蓄積されるのを待ちます

キューが x 回の呼び出し (x < X) を受信した場合、別のタスクが合計 >= X をプッシュするまで、呼び出し元のタスクはブロックされます。N * x 回の呼び出しを行いたいタスクが 1 つしかない場合、スタックします。

通常、アプリケーションで多くのタスクが実行されている場合、この問題は断続的にしか発生しない可能性があります。負荷が異常に低いか、クリーン シャットダウンが発生している場合です。

タイムアウトを追加することでこれを解決できます。これにより、制限時間内にリクエストが追加されなかった場合、および/または最初のリクエストが制限時間より長く待機している場合でも、キューはバッチ処理されたリクエストを送信します。

もちろん、このコードを書き直して、親クラスでリクエストのリストを作成し、サービスを呼び出すこともできます。

おそらく、あなたはこのアプローチで正しい軌道に乗っています。委任、継承、ラムダ メソッド、またはジェネレーターの拡張によって、生成されたメソッドの実装をハンドコーディングされた実装に置き換える方法を見つけることができますか?


...私の本当の問題で、このコードはすべて生成されます。

コードのどの部分が生成され (変更が難しい)、この問題を解決するためにコードのどの部分を変更できるかがよくわかりません。

  1. Child.RemoteCall()
  2. Parent.SumChildren()
  3. 上記のどちらでもありません。

上記のいずれでもない場合は、問題を解決するために何かを変更できる必要があります。親と子のインスタンスは AbstractFactory によって構築されていますか? その場合、動作の非機能的な側面を変更するために使用できる子インスタンスにプロキシを挿入できる可能性があります。

于 2009-12-05T12:22:10.890 に答える
0

(スペースは回答ボックスを使用)

考えてくれてありがとう。

「こうすれば…」: リポジトリから生成されたコードを扱います。この問題のハンドコーディングされた例を扱うとき、開発者はこれを見つけて改善することができます。コードを生成すると、一連の問題の例から一般的なケースを抽出するのは非常に困難です。これはかなり複雑になる可能性があるため、私の戦略は分割して征服することです。ドアを出る子の機能の中を見なければならない場合。

「私はこのリンクを見つけました...」: Futures を見てきましたが、それは、アイドル スレッドがあるときに並列化できるフォーク メカニズムです。

TPL は、作業を小さなビットに分割することを目的としているようです。私がやりたいのは、これらのビットのいくつかを取り、しばらくの間別の構成にまとめてから、並列実行のために再び分割することです。(私は、まだこれを精神的に噛んでいると思います...)

「もう 1 つの考え」: 繰り返しになりますが、分割統治戦略によってここまでたどり着くことができました。だから私は大きな問題を小さなビットに分割し、それらを解決してから、ビットを元に戻します. 私は、各アリが単純なルール (またはかんばん、これは同様の原則です) に従うアリのコロニーを考えるのが好きです。これは、非常に複雑になり、急速に行き詰まる中央管理機能 (クエリ オプティマイザ) とは対照的です。

親が並列化可能な方法で 50 の子を呼び出すだけで、同じリモート リソースを指しているという理由だけで、これらの個別のタスクをまとめてバッチ処理できる場合、これはすばらしいことです。

ここでの主なハードルは、呼び出し元のタスク (またはスレッドなど、実行単位) をブロックし、別のタスクにそれらのバッチの作業をピックアップさせ、それを実行し、すべてのタスクが存在するコレクションに答えを入れる方法です。彼らの仕事を置くと、彼らは再び彼らを目覚めさせます。(そして効率的な方法で..)。

George Chrysanthakopoulos (CCR を作成した人物) が、yield return ステートメントは彼がそのようなことに慣れていたものだと言ったことを覚えていると思います。Channel9 でもう一度そのインタビューを探してみます。

よろしくGJ

于 2009-12-07T12:16:35.887 に答える