[解決済み】Parallel.ForEachでawaitをネストする【重複あり
質問
メトロアプリで、WCFの呼び出しを何度も実行する必要があります。かなりの数の呼び出しを行う必要があるため、並列ループで実行する必要があります。 問題は、WCFコールがすべて完了する前に並列ループが終了してしまうことです。
これを期待通りに動作させるには、どのようにリファクタリングすればよいでしょうか。
var ids = new List<string>() { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
var customers = new System.Collections.Concurrent.BlockingCollection<Customer>();
Parallel.ForEach(ids, async i =>
{
ICustomerRepo repo = new CustomerRepo();
var cust = await repo.GetCustomer(i);
customers.Add(cust);
});
foreach ( var customer in customers )
{
Console.WriteLine(customer.ID);
}
Console.ReadKey();
解決方法は?
の背後にある全体のアイデア
Parallel.ForEach()
は、スレッドの集合を持ち、各スレッドがコレクションの一部を処理することです。お気づきのように、これは
async
-
await
ここで、非同期呼び出しの間、スレッドを解放したい場合。
をブロックすることで、それを「修正」することができます。
ForEach()
スレッドの意味がなくなってしまいます。
async
-
await
.
何ができるかというと
TPLデータフロー
の代わりに
Parallel.ForEach()
をサポートし、非同期の
Task
をうまく使っている。
具体的には、あなたのコードを
TransformBlock
に変換し、それぞれのidを
Customer
を使用しています。
async
ラムダを使用します。このブロックは並列に実行されるように設定することができます。このブロックを
ActionBlock
を書き込むことで、それぞれの
Customer
をコンソールに送信します。
ブロックネットワークを設定した後は
Post()
各IDを
TransformBlock
.
コードでは
var ids = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
var getCustomerBlock = new TransformBlock<string, Customer>(
async i =>
{
ICustomerRepo repo = new CustomerRepo();
return await repo.GetCustomer(i);
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
});
var writeCustomerBlock = new ActionBlock<Customer>(c => Console.WriteLine(c.ID));
getCustomerBlock.LinkTo(
writeCustomerBlock, new DataflowLinkOptions
{
PropagateCompletion = true
});
foreach (var id in ids)
getCustomerBlock.Post(id);
getCustomerBlock.Complete();
writeCustomerBlock.Completion.Wait();
の並列性を制限したいのでしょうが、そのためには
TransformBlock
をある小さな定数に設定します。また、容量を制限して
TransformBlock
を使い、非同期にアイテムを追加していきます。
SendAsync()
例えば、コレクションが大きすぎる場合などです。
あなたのコードと比較した場合の追加メリットとして、(うまくいった場合)1つのアイテムが終了するとすぐに書き込みを開始し、すべての処理が終了するまで待つ必要がないことです。
関連
-
[解決済み】"出力タイプがクラスライブラリのプロジェクトは直接起動できない"
-
[解決済み] メンバー '<メンバー名>' にインスタンス参照でアクセスできない
-
[解決済み】"The ConnectionString property has not been initialized "を修正する方法
-
[解決済み] 'IEnumerable<SelectListItem>' 型の ViewData アイテムで、キーが国であるものは存在しない。
-
[解決済み] forEachループでasync/awaitを使用する
-
[解決済み] async」と「await」の使い方とタイミング
-
[解決済み] 複数のタスクにasync/awaitを使用する
-
[解決済み] C#でawaitを使わずに非同期メソッドを安全に呼び出す方法
-
[解決済み】Parallel.ForEachを制限するには?
-
[解決済み】Parallel.ForEachとTask.Run、Task.WhenAllとの比較
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] [Solved] 不正な文字列値: '\xEFxBFxBD' for column
-
[解決済み】Entity FrameworkからのSqlException - セッション内で他のスレッドが動作しているため、新しいトランザクションは許可されません。
-
[解決済み】「...は'型'であり、与えられたコンテキストでは有効ではありません」を解決するにはどうすればよいですか?(C#)
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】ランダムなブーリアンを生成する最速の方法
-
[解決済み】C#のequal to演算子でtextとvarcharのデータ型は互換性がない
-
VSでscanfエラーを恒久的に解決するには、ソースファイルを作成し、自動的に#define _CRT_SECURE_NO_WARNINGS 1を追加してください。
-
[解決済み】linq selectで非同期await。
-
[解決済み】非同期ラムダによる並列foreach
-
[解決済み] 非同期I/Oの同時処理量を制限するには?