同时执行所有任务并等待完成?

时间:2015-10-05 15:52:37

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

我想要同时执行一系列异步方法。对于它们是否成功执行,这些方法中的每一个都返回true或false。他们的结果也记录在我们的审计跟踪中,以便我们可以诊断问题。

我的一些功能并不依赖于所有这些成功执行的方法,我们完全希望其中一些方法不时失败。如果他们确实失败了,程序将继续执行,它只会提醒我们的支持人员他们需要纠正这个问题。

我正在试图弄清楚所有这些函数同时执行的最佳方法是什么,但是只有在它们全部开始执行之后才让父函数等待它们。如果任何函数失败,父函数将返回False,这将提醒我的应用程序停止执行。

我的想法是做类似的事情:

public async Task<bool> SetupAccessControl(int objectTypeId, int objectId, int? organizationId)
{
    using (var context = new SupportContext(CustomerId))
    {
        if (organizationId == null)
        {
            var defaultOrganization = context.Organizations.FirstOrDefault(n => n.Default);
            if (defaultOrganization != null)  organizationId = defaultOrganization.Id;
        }
    }

    var acLink = AcLinkObjectToOrganiation(organizationId??0,objectTypeId,objectId);

    var eAdmin = GrantRoleAccessToObject("eAdmin", objectTypeId, objectId);
    var defaultRole = GrantRoleAccessToObject("Default", objectTypeId, objectId);

    await acLink;
    await eAdmin;
    await defaultRole;

    var userAccess = (objectTypeId != (int)ObjectType.User) || await SetupUserAccessControl(objectId);

    return acLink.Result && eAdmin.Result && defaultRole.Result && userAccess;
}

public async Task<bool> SetupUserAccessControl(int objectId)
{
    var everyoneRole = AddToUserRoleBridge("Everyone", objectId);
    var defaultRole = AddToUserRoleBridge("Default", objectId);

    await everyoneRole;
    await defaultRole;

    return everyoneRole.Result && defaultRole.Result;
}

有更好的选择吗?我应该以任何方式进行重组吗?我只是试图加快执行时间,因为我有一个父函数执行近20个其他函数,这些函数彼此独立。即使它是最慢的,没有异步,它只需要大约1-2秒来执行。但是,这将被扩展为最终使父调用执行数百次(批量插入)。

1 个答案:

答案 0 :(得分:6)

异步方法有一个同步部分,它是在达到未完成任务的第一个await之前的部分(如果没有,则整个方法同步运行)。该部分使用调用线程同步执行。

如果要在不并行化这些部分的情况下同时运行这些方法,只需调用方法,收集任务并使用Task.WhenAll一次等待所有这些方法。完成所有任务后,您可以查看单个结果:

async Task<bool> SetupUserAccessControlAsync(int objectId)
{
    var everyoneRoleTask = AddToUserRoleBridgeAsync("Everyone", objectId);
    var defaultRoleTask = AddToUserRoleBridgeAsync("Default", objectId);

    await Task.WhenAll(everyoneRoleTask, defaultRoleTask)

    return await everyoneRoleTask && await defaultRoleTask;
}

如果您确实想要并行化该同步部分,则需要多个线程,而不是简单地调用异步方法,而是使用Task.Run卸载到ThreadPool线程:

async Task<bool> SetupUserAccessControlAsync(int objectId)
{
    var everyoneRoleTask = Task.Run(() => AddToUserRoleBridgeAsync("Everyone", objectId));
    var defaultRoleTask = Task.Run(() => AddToUserRoleBridgeAsync("Default", objectId));

    await Task.WhenAll(everyoneRoleTask, defaultRoleTask)

    return await everyoneRoleTask && await defaultRoleTask;
}

如果您的所有方法都返回bool,您可以收集列表中的所有任务,从Task.WhenAll获取结果并检查是否全部返回true

async Task<bool> SetupUserAccessControlAsync(int objectId)
{
    var tasks = new List<Task<bool>>();
    tasks.Add(AddToUserRoleBridgeAsync("Everyone", objectId));
    tasks.Add(AddToUserRoleBridgeAsync("Default", objectId));

    return (await Task.WhenAll(tasks)).All(_ => _);
}