Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 循环内的async/await是否会造成瓶颈?_C#_Multithreading_Loops_Async Await - Fatal编程技术网

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

C# 循环内的async/await是否会造成瓶颈?,c#,multithreading,loops,async-await,C#,Multithreading,Loops,Async Await,例如,假设我有以下代码: private async Task ManageClients() { for (int i =0; i < listClients.Count; i++) { if (list[i] == 0) await DoSomethingWithClientAsync(); else await DoOtherThingAsync(); } DoOther

例如,假设我有以下代码:

private async Task ManageClients()
{
    for (int i =0; i < listClients.Count; i++)
    {
        if (list[i] == 0)
            await DoSomethingWithClientAsync();
        else
            await DoOtherThingAsync();
    }

    DoOtherWork();
}
private async Task ManageClients()
{
for(int i=0;i
我的问题是:

1。for()是否会继续处理列表中的其他客户端?或者 将等待,直到它完成其中一项任务

2.在循环中使用async/await是否是一种好的做法

3.可以用更好的方法吗


我知道这是一个非常简单的示例,但我正在尝试想象如果该代码是一个具有数千个客户端的服务器,会发生什么情况。

在您的代码示例中,当循环到达
wait
时,代码将“阻塞”,这意味着在第一个客户端完成之前不会处理其他客户端。这是因为,虽然代码使用异步调用,但它是使用同步逻辑思维编写的

异步方法应该更像这样:

private async Task ManageClients()
{
    var tasks = listClients.Select( client => DoSomethingWithClient() );
    await Task.WhenAll(tasks);
    DoOtherWork();
}

请注意,只有一个
wait
,它同时等待所有客户端,并允许它们以任何顺序完成。这避免了循环在等待第一个客户端时被阻塞的情况。

如果执行异步函数的线程正在调用另一个异步函数,则在看到对第三个异步函数的调用之前,该另一个函数将被视为非异步函数来执行。第三个异步函数的执行也如同它不是异步函数一样

这将继续,直到线程看到等待

线程不是什么都不做,而是向上移动调用堆栈,查看调用方是否在等待被调用函数的结果。如果没有,线程将继续调用函数中的语句,直到看到等待。线程再次进入调用堆栈,查看是否可以继续

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

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();
一旦您需要任务的结果,if取决于您想对其执行什么操作。如果一项任务已完成,但另一项任务未完成,是否可以继续处理

var someResult = await taskDoSomething;
ProcessResult(someResult);
var someOtherResult = await taskDoSomethingelse;
ProcessBothResults(someResult, someOtherResult);
如果需要所有任务的结果才能继续,请使用Task.whall:

Task[] allTasks = new Task[] {taskDoSomething, taskDoSomethingElse);
await Task.WhenAll(allTasks);
var someResult = taskDoSomething.Result;
var someOtherResult = taskDoSomethingElse.Result;
ProcessBothResults(someResult, someOtherResult);
回到你的问题

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

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

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();

您希望发生的事情可能重复?如果您记得只应在代码没有任何用处的地方使用
await
,直到右边的任务完成,这是否回答了您的问题?单词
await
清楚地告诉您,它将等待任务完成。此外,如果DoOtherwork不需要任务的结果,您可以将其放在等待之前,以便任务和DoOtherwork并行运行,而不是顺序运行。如果DoSomethingWithClient中的代码影响程序的状态,这可能会改变程序的行为。这不是更异步,只是不同而已。原始代码也非常异步,与调用者交错。更好的方法在很大程度上取决于环境和任务是否独立。问题是DoSomethingWithClient()是一个I/O操作,因此理想情况下,我希望尽快发送结果,但也希望同时处理10个客户端I/O。这是一种更好的方法吗?这种方法允许在等待第一个I/O操作完成之前启动所有I/O操作。是的,如果你想要一个更短的整体执行时间,它可能会更好。非常感谢你的详细回答,它帮助我理清了一些事情。但是,如果DoSomethingWithClientAsync是一个I/O操作,而les说10个客户端同时需要结果,那么等待的时间是什么呢?所有这些都是最好的方法吗?
foreach(var client in clients)
{
    if (list[i] == 0)
        await DoSomethingWithClientAsync());
    else
        await DoOtherThingAsync();
}