异步等待线程行为和问题

时间:2018-11-28 00:01:16

标签: c# .net multithreading asynchronous async-await

仅调用一个内衬async await方法的async await方法的用途是什么?它们跨越多少个线程?您最终会消耗多少CPU? 嗨,最近我看到了许多使用async和await关键字的方法。当仍然按如下所示应用它们时,我仍然不能全神贯注于它们的用法和基本行为以及它们的优势。当他们将CPU用于所有事物时,我也发现CPU出现问题(运行100%),我将thread.run视为某些情况下CPU利用率的元凶。

myController.cs

[HttpPost]

[ProducesResponseType(body)]

public async Task<IActionResult> Post([FromBody]Body body){

_MyClassService.sendMessage(body);

return Ok(body);

}

我的服务班

Myclass.cs

private async void sendMessage(){

await SendToProperChannel();

}



private async Task SendToProperChannel(){

await DoWorkInProperChannel();

}



private Task<int> DoWorkInProperChannel(){

await SomethingThatTakes5Seconds();

return 1+1;

}

据我所知。

我们正在使控制器请求异步,以便不阻塞主线程,从而允许在控制器级别获得更高的吞吐量。

我们还使所有函数异步,以不阻塞调用这些方法的上层线程。

我也理解,由于等待的人很多,每个人都返回一个任务,但是还有一个线程正在处理该工作,等待完成。

我仍然不清楚线程号,但是我相信我们会产生一个以上的线程来满足一个请求。

我的问题。

如果上部方法没有响应就无法继续使用,等待一根衬管有什么用?实际上,该API可以接收更多的吞吐量,但是从那里开始,所有内容都将实现某种程度的同步,并且还会产生更多的线程,只是为了在类中的方法之间跳转似乎并不健康。

如果我仅在一个班轮上等待,在此特定代码中,结果将与删除等待中的结果不同吗?

由于所有方法都不会阻塞,因此它们也将处理更多的吞吐量?

启动异步方法并等待同一方法内部的响应方式的语法如何。

示例:

private async Task<int> myAsyncWorkerMethod(){

var myNeededValue=methodThatINeed();

var mySecondValue=methodWithSecondValue();

await myNeededValue;

await mySecondValue;

return myNeededValue+mySecondValue;

}

异步并等待仅拥有一个线程池来处理所有下游调用有什么好处,您可以轻松地控制线程池的大小并轻松检测线程饥饿和队列深度? (我可能在这里使用了一些不适用的Java术语)

想法

在其他语言中,我看到了线程上下文更改的影响,如果您的CPU不够强大或者由于线程池大小而导致线程饥饿,那么.net不受控制的线程池不会具有相同的影响,而尽可能多地使用CPU?

如果您需要异步调用来返回对await语句的响应,则无需创建异步调用。仅当您需要对上述方法做一些工作时才需要进行异步处理吗?

即使您正在等待另一个类的方法结果,除非您不想阻塞主线程,也不要等待它。

预先感谢

1 个答案:

答案 0 :(得分:2)

我将尝试一次回答您的观点和问题:

  

“我们正在使控制器请求异步,以便不阻塞主线程,从而允许在控制器级别接收更高的吞吐量。”

不,那是完全不正确的。打开适当的编译器异常,您会发现使用async而不使用await是浪费时间,这没有任何价值,并且会生成无用的IL代码。

  

“我也理解,由于等待的人很多,每个人都返回一个任务,但是还有一个线程正在处理正在等待完成的工作。”

There is no thread

  

“我仍然不清楚线程号,但是我相信我们会产生多个线程来满足一个请求。”

如上所述,这也是无效的。

  

如果上部方法如果没有响应就无法继续,那么等待一根衬管有什么用?

基本上没有,代码可能只是:

private async void sendMessage()
{    
    await DoWorkInProperChannel();
}

private Task<int> DoWorkInProperChannel()
{
    // `await Thread.Sleep()` is not valid, `Sleep` returns `void` 
    await Task.Delay(1000);

    return 1+1;
}

注意:上面的代码没有创建一个新线程;不在原始版本或我的版本中。

  

如果我仅在一个班轮上等待,在此特定代码中,结果将与删除等待中的结果不同吗?

一点也不,您需要return生成的Task才能使代码相同。当然,对于async void方法来说,除了不能返回任何内容。

private async Task<int> myAsyncWorkerMethod()
{
    var myNeededValue=methodThatINeed();
    var mySecondValue=methodWithSecondValue();
    await myNeededValue;
    await mySecondValue;

    return myNeededValue+mySecondValue;
}

这被称为并行异步代码,与上一个示例无关。是否可以使用并行代码取决于您的工作。

  

在其他语言中,我看到了线程上下文更改的影响,如果您的CPU不够强大,或者由于线程池大小而导致线程饥饿,那么.net不受控制的线程池不会具有相同的影响,而尽可能多地使用CPU?

您发布的代码中没有一个上下文更改,因此这无关紧要。

  

即使您正在等待另一个类的方法结果,除非您不想阻塞主线程,也不要等待它。

您正在使用ASP.NET Core,没有主线程。