2017-02-21 11 views
0

を待って、私は次のシナリオがあります。新しい非同期を必要とする各タスクで複数のタスクを持つシナリオで非同期/のawait使用方法/

お客様は、それらのそれぞれは、付属のカードの番号を持って、アカウントの数を持っています。

今、私は複数の顧客のカードで口座を照会する必要があるという要求があります。アカウントとカードを別々に照会する非同期メソッドがあります(FindAccounts(string customer)FindCards(string[] accounts))。

だから私はこの方法があります。これは、それはあなたがカードを照会することができる前に終了するすべての顧客の口座を待つ必要が問題を持って動作しますが

public async Task<Data> FindCustomersWithCards(string[] customers) 
{ 
    var accountsTasks = customers.Select(_service.FindAccounts); 
    var accounts = await Task.WhenAll(accountsTasks); 

    var cardsTasks = accounts.Select(_service.FindCards); 
    var cards = await Tasks.WhenAll(cardsTasks)   
    ... 
} 

を。特定の顧客を照会するアカウントが終了すると(他の顧客を待たずに)、より効率的な実装が行われ、顧客アカウントのカードを照会します。

async/awaitでこれを行うことができるのですかと私の質問です。 ContinueWithで管理できると思いますが、async/awaitContinueWithの方法で100%混同しても問題ありません。

+0

あなたは正しいです、あなたが欲しいもののように聞こえます。アカウントごとに「アカウントを取得してカードを取得する」という大きなタスクを構築します。 – Juan

+0

2つのアプローチを混在させるとどうなりますか?あなたはそれの欠点を知っていますか? –

+0

ええ、私はそれを混合することを意味し、あなたはContinueWithで待つことができます、基本的にあなたはタスクを返して何かで待つことができますし、ContinueWithはありません。メソッドのシグネチャを表示すると、oyuにサンプルコード – Juan

答えて

3

その中に顧客と非同期で、それを分割する方が賢明かもしれません:

private async Task<Card> FindCardForCustomerAsync(string customer) 
{ 
    var account = await _service.FindAccountAsync(customer); 
    return await _service.FindCardAsync(account); 
} 

public async Task<Data> FindCustomersWithCards(string[] customers) 
{ 
    var cardsTasks = customers.Select(FindCardForCustomerAsync); 
    var cards = await Tasks.WhenAll(cardsTasks) 
    … 
} 

しかし、それはどのようにあなたのFindAccountsFindCards作業の効率のバランスを考慮する価値があります。例えば。単一のSELECTがデータベースにプッシュされて動作する場合、複数の小さな作業ビットに変換することのより大きな並行性により、大きなオーバーヘッドの価値があるわけではありません。 20または200の結果を待つことは、1を待つことよりわずかに遅いだけで、余分な接続が考慮される前でさえ、20の要求に分割することは非常にわずかです。

+0

ありがとうございます。今は明らかになっているようですが、何らかの理由で自分自身を考えなかったのです。 @ Panagiotis Kanavosはコメントで同じ解決策を指摘している。 1つのSELECTを持たない理由は、データストアを制御できず、これらの断片化されたクエリのみを許可するためです。チャンスがあれば、私はむしろそれらをすべて照会したいと思うでしょう:) –

+0

'FindAccounts'がシーンの中でいくつかの呼び出しを行っている場合、オッズは確かに改善され、少なくとも悪化させないでしょう。 –

+0

'FindAccounts'は本当に1つの呼び出ししかしませんが、カードを続ける前にすべての顧客のアカウントを見つけなければならないという問題がありました:) –

0

tasks per customerアプローチが利益をもたらすかどうかは分かりませんが、それを見つける最も良い方法はシナリオをテストすることです。

私は、顧客ごとにタスクを実行できるように最初のアプローチをどのように変更することができるかという簡単な例を示しました。
あなたはこれを管理できると述べましたが、私はここに投稿して、それに興味のある誰もがそれを再生できるようにしたかったのです。

私はTask.Run(...)を使って非同期タスクをシミュレートしました。

public class Account 
{ 
    public string AccountName { get; set; } 
    public string CustomerName { get; set; } 
} 

public class Card 
{ 
    public string CardName { get; set; } 
    public string AccountName { get; set; } 
} 

public List<Account> Accounts { get; set; } 
public List<Card> Cards { get; set; } 

//OLD 
public async Task<string[]> FindAccounts(string customer) 
{ 
    return await Task.Run(() => 
    { 
     return Accounts.Where(a => a.CustomerName == customer).Select(a => a.AccountName).ToArray(); 
    }); 
} 

//OLD 
public async Task<string[]> FindCards(string[] accounts) 
{ 
    return await Task.Run(() => 
    { 
     return Cards.Where(c => accounts.Contains(c.AccountName)).Select(a => a.CardName).ToArray(); 
    }); 
} 

//NEW 
public async Task<string[]> FindCards(Task<string[]> findAccountsTasks) 
{ 
    return await Task.Run(async() => 
    { 
     var accounts = await findAccountsTasks; 
     return Cards.Where(c => accounts.Contains(c.AccountName)).Select(a => a.CardName).ToArray(); 
    }); 
} 

//NEW 
public async Task<string[]> FindCards(string customer) 
{ 
    return await await FindAccounts(customer).ContinueWith(FindCards); 
} 

private async void button7_Click(object sender, EventArgs e) 
{ 
    Accounts = new List<Account> 
    { 
     new Account {CustomerName = "Tomas", AccountName = "TomasAccount1"}, 
     new Account {CustomerName = "Tomas", AccountName = "TomasAccount2"}, 
     new Account {CustomerName = "Tomas", AccountName = "TomasAccount3"}, 
     new Account {CustomerName = "John", AccountName = "JohnAccount1"} 
    }; 

    Cards = new List<Card> 
    { 
     new Card {AccountName = "TomasAccount1", CardName = "TomasAccount1Card1"}, 
     new Card {AccountName = "TomasAccount1", CardName = "TomasAccount1Card2"}, 
     new Card {AccountName = "TomasAccount1", CardName = "TomasAccount1Card3"}, 
     new Card {AccountName = "TomasAccount1", CardName = "TomasAccount2Card1"}, 
     new Card {AccountName = "JohnAccount1", CardName = "JohnAccount1Card1"}, 
     new Card {AccountName = "JohnAccount1", CardName = "JohnAccount1Card2"}, 
    }; 

    var customers = new List<string> { "Tomas", "John" }.ToArray(); 

    //OLD 
    var accountstasks = customers.Select(FindAccounts); 
    var accounts = await Task.WhenAll(accountstasks); 

    var cardTasks = accounts.Select(FindCards); 
    var cards = await Task.WhenAll(cardTasks); 

    //NEW 
    cardTasks = customers.Select(FindCards); 
    cards = await Task.WhenAll(cardTasks); 
} 
+0

あなたの提案をお寄せいただきありがとうございます。明らかに、より簡単で分かりやすい解決策がありました:) –