2015-10-05 70 views
4

我有一系列我想同时执行的异步方法。这些方法中的每一个都会返回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秒。然而,这将被放大以最终使该父呼叫执行数百次(批量插入)。

+0

我曾经使用Parallel.Invoke这个东西。 –

+3

你可能想看看'Task.WhenAll'。对于结果值,很难说不知道涉及的一半类型...... –

+0

幸运的是,如果我不需要将值传递给父级(或等待它们用于其他函数),则所有函数将返回一个真实或错误的价值。 –

回答

6

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

如果要同时运行这些方法而不平行化这些部分,只需调用方法,收集任务并使用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(_ => _); 
} 
+0

我并不担心它们完全并发地执行,我只是想确保每个执行都尽可能快地执行而不会阻塞下一个调用的执行。 –

+1

@Jdsfighter这些句子互相矛盾。如果您希望第二个操作尽快启动,那么您需要第一个操作来尽快释放调用线程。这意味着甚至将同步部分卸载到不同的线程。 – i3arnon

+0

每一个调用都执行一系列数据库功能。我只想确保我可以快速执行这些功能而不会阻塞调用线程长时间(如同步数据库调用)。 –