29

Silverlight WCF サービス プロキシのライフサイクルのトピックは、私にはあまり明確ではありません。ここでさまざまな資料、リソース、回答を読みましたが、それらを使用する最善の方法を完全には理解していません。

現在、Silverlight 4.0 でカスタム バイナリ バインドを使用しています。

Silverlight でのプロキシの作成はコストのかかる操作ですか? プロキシ インスタンスをコードで共有するか、新しいものを作成する方がよいでしょうか? 複数のスレッドがアクセスする場合に共有する場合、ロックを行う必要がありますか?

プロキシのエラーはプロキシの状態に障害を起こすため、プロキシを共有することは良い考えではないと思いますが、作成にはコストがかかると読んだので、ここで何をすべきかは 100% 明確ではありません。

また、閉じると、Silverlight WCF サービス クライアントは CloseAsync メソッドのみを提供します。また、プロキシは、閉じるときに特定のロジックを使用する必要があります (プロキシに障害が発生した場合は、Silverlight で同期されている Abort() を呼び出す必要があり、そうでない場合は、同期ではない CloseAsync を呼び出す必要があります)。

多くの公式の MS プロキシからの Silverlight サンプルは、まったく閉じられていません。それは単に材料の欠陥なのか、それとも予想されるアプローチなのか?

トピックは私にとって非常に重要であり、現在私が持っていない考慮すべきすべてのことを明確に理解したい.

(この質問は、Silverlight 3 での WCF サービス クライアント プロキシの適切なライフサイクルとは何ですか?が私の近くに表示されるのを見ましたが、回答の質に満足しているとは言えません)

WCF プロキシの使用、作成、終了などを行うサンプル コードを実際に見てみたいと思います。また、最も重要なこととして、それが最善の方法である理由を説明しています。また、問題の性質上、Silverlight で WCF プロキシを使用 (作成、再利用、閉じる) するための単一の一般的なベスト プラクティス/パターンが必要であると考えています (現在はそう考えています)。

4

2 に答える 2

8

概要: ベスト プラクティスは、使用する Web サービス クライアントをインスタンス化してから、範囲外にしてガベージ コレクションを取得することだと思います。これは、Microsoft から提供されたサンプルに反映されています。正当化は次のとおりです...

完全: 私が見つけたプロセスの最も完全な説明は、How to: Access a Service from Silverlight にあります。ここでの例は、Web サービス クライアントをインスタンス化し、(クライアントを閉じる必要なく) 範囲外にできるようにする典型的なパターンを示しています。Web サービス クライアントは、オブジェクトがガベージ コレクションされるときに、必要に応じて管理されていないリソースを解放する Finalize メソッドを持つ ClientBase から継承します。

私は Web サービスを使用したかなりの経験があり、プロキシを使用し、使用する直前にインスタンス化してから、ガベージ コレクションを許可します。このアプローチで問題が発生したことはありません。Wenlong Dong のブログで、プロキシの作成にはコストがかかると書かれていましたが、.NET 3.5 ではパフォーマンスが向上したとのことです (それ以降、再び向上したのでしょうか?)。私言えることは、パフォーマンスは相対的な用語であり、取得するデータのサイズが小さい場合を除き、接続を作成するよりもシリアル化/逆シリアル化と転送にはるかに多くの時間が費やされるということです. これは確かに私の経験であり、最初にこれらの領域で最適化する方がよいでしょう.

最後に、これまでの私の意見では不十分かもしれないので、簡単なテストを書きました。Visual Web Developer 2010 Express で提供されているテンプレートを使用して、Silverlight 対応の Web サービスを作成しました (既定の void メソッドは と呼ばれますDoWork())。次に、サンプルの Silverlight クライアントで、次のコードを使用して呼び出しました。

int counter=0;
public void Test()
{
    ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
    client.DoWorkCompleted += (obj, args) => 
    { 
        counter++;
        if (counter > 9999)
        {
            for(int j=0;j<10;j++) GC.Collect();
            System.Windows.MessageBox.Show("Completed");
        }
    };
    client.DoWorkAsync();
}

次に、Test メソッドを呼び出してfor(int i=0;i<10000;i++) Test();、アプリケーションを起動しました。アプリの読み込みと Web サービスの呼び出し (10,000 回すべて) を完了するのに 20 秒強かかりました。Web サービスの呼び出しが行われている間、プロセスのメモリ使用量が 150MB を超えていましたが、呼び出しが完了してGC.Collect()呼び出されると、メモリ使用量はその半分以下に減少しました。完璧なテストとはほど遠く、メモリ リークがないこと、または無視できるレベルであることを確認できたようです (すべて別のクライアント インスタンスを使用して 10,000 回の Web サービス呼び出しを呼び出すことはおそらく一般的ではないと考えてください)。また、プロキシ オブジェクトを保持し、障害が発生して再度開く必要があることを心配するよりも、はるかに単純なモデルです。

テスト方法論の正当化: 私のテストでは、2 つの潜在的な問題に焦点を当てました。1 つはメモリ リークで、もう 1 つはオブジェクトの作成と破棄に費やされたプロセッサ時間です。クラスを提供する会社 (Microsoft) が提供する例に従うことをお勧めします。ネットワークの効率が気になる場合は、これらのオブジェクトを適切に作成/破棄してもネットワークの遅延に影響しないため、この例で問題はないはずです。費やされた時間の 99% がネットワーク時間である場合、1% の理論上の改善のために最適化することは、おそらく開発時間の点で無駄です (得られる利点さえあると仮定すると、私のテストではほとんどないことが明らかに示されていると信じています/なし)。はい、ネットワーク呼び出しはローカルでした。つまり、10,000 回のサービス呼び出しの過程で、オブジェクトの待機に費やされるのは約 20 秒だけです。これは、オブジェクトの作成に費やされたサービス呼び出しごとに約 2 ミリ秒を表します。Dispose を呼び出す必要性については、必要がないように見えるだけで、それを呼び出すべきではありません。忘れた場合 (または単に忘れた場合)、私のテストでは、これらのオブジェクトの Finalize で Dispose が呼び出されていると信じていました。それでも、Dispose を自分で呼び出す方がおそらく効率的ですが、それでも効果は無視できます。ほとんどのソフトウェア開発では、(重大なメモリ リークがない限り) このような問題を突き止めるよりも、より効率的なアルゴリズムとデータ構造を考え出すことで、より多くの利益が得られます。XML に基づくシステムよりも効率的なデータ転送オプションがあるため、より効率が必要な場合は、おそらく Web サービスを使用しない方がよいでしょう。

于 2011-08-24T02:21:44.573 に答える
0

プロキシの作成は、呼び出しのラウンドトリップに比べて費用がかかりません。CloseAsync他の非同期メソッドを呼び出した直後に呼び出すという解説を見たことがありますが、これには欠陥があるようです。理論的には、クローズは保留状態に移行し、他の非同期呼び出しが終了した後に発生します。実際には、呼び出しが驚くほど迅速に障害で終了しCloseAsync、チャネルがすでに障害を起こしているためにそれ自体が障害を起こすのを見てきました。

私がやったことは、引数と型のコールバックを受け入れるCaller<TResult>いくつかのジェネリックメソッドオーバーロードを持つジェネリッククラスを作成することです。裏で、はイベントを配線し、完了の理由がエラーによるものかどうかを確認します。エラーの場合、それはチャネルになります。エラーがない場合は、コールバックを呼び出してから呼び出します。これにより、障害状態でチャネルを使用しようとするなどの「ばかげた」エラーが防止されます。CallAsyncAction<TResult>CallerXxxCompletedAbortCloseAsync

上記のすべては、create-proxy-make-call-discard-use-of-proxyモデルを前提としています。連続して多数の通話を発信する必要がある場合は、このアプローチを適用して、実行中の通話の数をカウントし、最後の通話が完了したら、閉じるか中止することができます。

呼び出しごとまたは関連する呼び出しのセットごとのプロキシ作成のオーバーヘッドが問題になることはまれです。オーバーヘッドが高すぎる場合にのみ、プロキシキャッシングまたは再利用戦略を追求します。リソースを長く保持するほど、失敗する可能性が高くなることを忘れないでください。少なくとも私の経験では、ライフタイムが短いほど、ユーザーが知覚するパフォーマンスが向上します。これは、ユーザーの割り込みが少なく、再試行ロジックを維持するために費用をかける必要がないためです。いつそれらを取り除くべきかを正確に知ることによって、あなたがメモリやリソースを漏らしていないことをより確信してください。

例が閉じていないという質問に関しては...まあ、これらは例であり、アプリケーションの存続期間全体にわたって実行する必要があることに関するすべての詳細ではなく、一般的な使用法を示しているため、通常は1次元で不完全です。

于 2011-08-27T01:00:50.920 に答える