【问题标题】:Issue when executing a list of tasks, that have multiple async calls inside each one执行任务列表时出现问题,每个任务中有多个异步调用
【发布时间】:2020-09-28 19:38:21
【问题描述】:

我得到了下面这段暂定的代码,它应该生成一个要同时执行的任务列表。 try...catch... 中的代码表示每个任务。但是代码块本身包含 3 个应该按顺序执行的异步调用,基本上第二个调用取决于第一个,第三个取决于第二个。

var syncActions = new List<SyncAction<ContactDto>>();
ContactDto contactDto = null;

var syncActionTasks = updatedNodes.Select(async node =>
{
    SyncAction<IUmbracoActiveCampaignEntity> syncActionResult;
    contactDto = Mapper.Map<ContactDto>(node);

    try
    {
        var firstAsyncCallResult = await this.Contacts
            .GetByEmailAsync<ContactsRoot>(contactDto.Email);

        //...(code omittted for brevity)...

        var secondAsyncCallResult = await this.Contacts
            .AddOrUpdateAsync(firstAsyncCallResult);

        //...(code omittted for brevity)...

        var thirdAsyncCallResult = await this.Contacts
            .GetAccountContactAssociation(secondAsyncCallResult);

    }
    catch (ActiveCampaignException ex)
    {
        // handle error
    }

    return Task.FromResult(contactDto);
})
.ToList();

var result = await Task.WhenAll(syncActionTasks);

//...(code omittted for brevity)...

我的经验是,当代码执行 firstAsyncCallResult 而不是继续执行其他 2 个异步调用时,它会跳回到代码的开头 SyncAction&lt;IUmbracoActiveCampaignEntity&gt; syncActionResult; 并且虽然所有代码都“正常”运行,但 var result = await Task.WhenAll(syncActionTasks); 行返回了正确数量的 contactDto 对象,但这些对象本身重复出现,并且不像预期的那样唯一。

任何线索,为什么以及什么可以调整以获得预期的结果?任何方向和建议将不胜感激。

【问题讨论】:

  • 您确定contactDtoMapperthis.Contacts 对象是线程安全的吗?希望它们是,因为它们将在没有同步的情况下被多个线程同时访问。还有变量syncActions 与其余代码有什么关系?

标签: c# asp.net-web-api async-await task-parallel-library


【解决方案1】:

我的经验是,当代码执行 firstAsyncCallResult 而不是继续执行其他 2 个异步调用时,它会跳回到代码的开头SyncAction&lt;IUmbracoActiveCampaignEntity&gt; syncActionResult;

是的,一旦第一个await 被命中,一个Task 将从 lambda 中返回,并且下一次迭代将开始。一旦从GetByEmailAsync 返回的Task 完成,该方法将恢复。

同样Task.FromResult 不应该用在async 方法中; async 方法隐式返回 Task,因此您不需要自己创建一个。只需返回 DTO:

return contactDto;

按照你的方式使用Task.FromResult,lambda 的返回类型是Task&lt;Task&lt;ContactDto&gt;&gt;

ToList() 的调用也是多余的,因为Task.WhenAll 接受已经从您的Select 返回的IEnumerable&lt;Task&lt;TResult&gt;&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    相关资源
    最近更新 更多