如何在具有多个任务的场景中使用async / await,每个任务都需要新的异步/等待

时间:2017-02-21 10:49:52

标签: c# .net asynchronous async-await task-parallel-library

我有以下情况:

客户拥有多个帐户,每个帐户都附有多张卡片。

现在我有一个请求,我需要在多个客户的卡上查询帐户。我有异步方法来分别查询帐户和卡片,即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/await进行管理,但我不能100%确定将ContinueWithAppServiceProvider.php方法混合使用。

2 个答案:

答案 0 :(得分: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个请求获得非常少,甚至在考虑所涉及的额外连接之前。

答案 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);
}