为了账号安全,请及时绑定邮箱和手机立即绑定

循环内的 async/await 是否会造成瓶颈?

循环内的 async/await 是否会造成瓶颈?

C#
12345678_0001 2021-10-23 16:37:32
假设我有以下代码,例如:private async Task ManageClients(){    for (int i =0; i < listClients.Count; i++)    {        if (list[i] == 0)            await DoSomethingWithClientAsync();        else            await DoOtherThingAsync();    }    DoOtherWork();}我的问题是:1.请问为()继续和处理其他客户端上的列表?,或者它会等待,直到它完成的任务之一。2.在循环中使用async/await是否是一个好习惯?3.能否以更好的方式完成?我知道这是一个非常简单的例子,但我试图想象如果该代码是一个拥有数千个客户端的服务器会发生什么。
查看完整描述

2 回答

?
GCT1015

TA贡献1827条经验 获得超4个赞

如果正在执行异步函数的线程正在调用另一个异步函数,则该另一个函数将被执行,就好像它不是异步的一样,直到它看到对第三个异步函数的调用。这第三个异步函数也被执行,就好像它不是异步的一样。


如此继续,直到线程看到等待。


线程并没有真正做任何事情,而是向上调用堆栈,以查看调用者是否没有等待被调用函数的结果。如果没有,线程继续调用函数中的语句,直到它看到等待。线程再次上升到调用堆栈以查看它是否可以在那里继续。


这可以在以下代码中看到:


var taskDoSomething = DoSomethingAsync(...);

// because we are not awaiting, the following is done as soon as DoSomethingAsync has to await:

DoSomethingElse();

// from here we need the result from DoSomethingAsync. await for it:

var someResult = await taskDoSomething;

您甚至可以在不等待的情况下调用多个子过程:


 var taskDoSomething = DoSomethingAsync(...);

 var taskDoSomethingElse = DoSomethingElseAsync(...);

 // we are here both tasks are awaiting

 DoSomethingElse();

一旦你需要任务的结果,如果取决于你想用它们做什么。如果一项任务已完成而另一项未完成,您能否继续处理?


var someResult = await taskDoSomething;

ProcessResult(someResult);

var someOtherResult = await taskDoSomethingelse;

ProcessBothResults(someResult, someOtherResult);

如果在继续之前需要所有任务的结果,请使用 Task.WhenAll:


Task[] allTasks = new Task[] {taskDoSomething, taskDoSomethingElse);

await Task.WhenAll(allTasks);

var someResult = taskDoSomething.Result;

var someOtherResult = taskDoSomethingElse.Result;

ProcessBothResults(someResult, someOtherResult);

回到你的问题


如果您有一系列需要启动可等待任务的项目,这取决于任务是否需要其他任务的结果。换句话说,如果任务 [1] 尚未完成,任务 [2] 可以启动吗?如果 Task[1] 和 Task[2] 同时运行,它们会相互干扰吗?


如果它们是独立的,则无需等待即可启动所有任务。然后使用Task.WhenAll等待,直到所有完成。任务调度程序会注意不要同时启动许多任务。但请注意,启动多个任务可能会导致死锁。仔细检查是否需要关键部分


var clientTasks = new List<Task>();

foreach(var client in clients)

{

    if (list[i] == 0)

        clientTasks.Add(DoSomethingWithClientAsync());

    else

        clientTasks.Add(DoOtherThingAsync());

}

// if here: all tasks started. If desired you can do other things:

AndNowForSomethingCompletelyDifferent();


// later we need the other tasks to be finished:

var taskWaitAll = Task.WhenAll(clientTasks);


// did you notice we still did not await yet, we are still in business:

MontyPython();


// okay, done with frolicking, we need the results:

await taskWaitAll;

DoOtherWork();

这是所有任务独立的场景:没有任务需要其他任务完成才能开始。但是,如果您需要在启动 Task[3] 之前完成 Task[2],则应该等待:


foreach(var client in clients)

{

    if (list[i] == 0)

        await DoSomethingWithClientAsync());

    else

        await DoOtherThingAsync();

}


查看完整回答
反对 回复 2021-10-23
  • 2 回答
  • 0 关注
  • 148 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信