使用 Async Await 是否可以避免线程耗尽?
Does Using Async Await Avoid Thread Exhaustion?
我们正在解决 .NET Core API
端点上的以下性能问题:
- 在较小的负载下,端点始终 returns 小于
500MS
。
- 当我们从 3 个浏览器访问端点时,每秒一个请求,它 变得越来越慢 (在添加第三个浏览器进行调用的一分钟内,响应时间下降到
50,000MS
或更糟。
- 每个额外的浏览器 添加 API 使用的线程,例如40 个线程基础,第二个浏览器命中端点导致 52 个线程,第三个峰值为 70,依此类推。
- 加载一个端点时,整个API returns 缓慢(所有端点)。这是我考虑 "thread exhaustion" 以及第 3 点的主要原因。
代码目前如下所示:
public IActionResult GetPresentationByEvent(int eventid)
{
return Authorized(authDto =>
{
var eventList = _eventService.GetPresentationByEvent(eventid);
return Ok(eventList)
})
}
我的理论是 return Authorized(authDto =>
持有一个线程直到它 returns,导致线程耗尽。
public async Task<IActionResult> GetPresentationByEvent(int eventid)
{
return Authorized(async authDto =>
{
Task<List<whatever>> eventList = _eventService.GetPresentationByEvent(eventid);
return Ok(eventList)
}
}
Authorized
是第三方库的一部分,所以我不能轻易测试这个。想知道这是否看起来像 problem/solution.
是的,async await 可以减少线程耗尽。简而言之,当您生成的任务多于 ThreadPool 可以处理的数量时,就会出现线程耗尽。
您可以在此处查看一些细微的细节:Thread starvation and queuing
你唯一需要记住的是你永远不应该在任务中阻塞。这意味着使用 async await 调用异步代码(永远不要在未完成的任务上使用 .Wait 或 .Result)。
如果您使用一些不使用异步等待模式的阻塞代码,您必须在专用线程(而不是任务线程队列)上生成它。
My theory is that return Authorized(authDto => holds a thread until it returns, leading to thread exhaustion.
是的。您可以通过查看其 return 值轻松判断方法是否同步。 IActionResult
不是等待类型,因此此方法将 运行 同步。
Authorized is part of a third-party library, so I can't test this easily. Would like to know if this looks like a likely problem/solution.
可能吧。这完全取决于 Authorized
是否可以处理异步委托。如果可以,那么这样的事情就可以了:
public async Task<IActionResult> GetPresentationByEvent(int eventid)
{
return Authorized(async authDto =>
{
Task<List<whatever>> eventList = _eventService.GetPresentationByEventAsync(eventid);
return Ok(await eventList);
});
}
注:
- 任务在传递给
Ok
或其他助手之前应该 await
ed。
- 这引入了
GetPresentationByEventAsync
,假设您的数据访问代码可以异步。
由于使 GetPresentationByEvent
异步可能需要一些工作,因此值得在尝试此之前调查 Authorized
是否可以采用异步委托。
Does Using Async Await Avoid Thread Exhaustion?
是也不是。异步代码(包括 async
/await
)确实使用较少的线程,因为它避免了阻塞线程。但是,仍然有一个限制。线程耗尽仍然是可能的,因为异步代码需要一个空闲线程才能完成。使用异步代码,通常您可以在 运行 陷入线程耗尽等可伸缩性问题之前实现一个或两个更大的可伸缩性。
有关 async
ASP.NET 的更多概念信息,请参阅 this MSDN article。
我们正在解决 .NET Core API
端点上的以下性能问题:
- 在较小的负载下,端点始终 returns 小于
500MS
。 - 当我们从 3 个浏览器访问端点时,每秒一个请求,它 变得越来越慢 (在添加第三个浏览器进行调用的一分钟内,响应时间下降到
50,000MS
或更糟。 - 每个额外的浏览器 添加 API 使用的线程,例如40 个线程基础,第二个浏览器命中端点导致 52 个线程,第三个峰值为 70,依此类推。
- 加载一个端点时,整个API returns 缓慢(所有端点)。这是我考虑 "thread exhaustion" 以及第 3 点的主要原因。
代码目前如下所示:
public IActionResult GetPresentationByEvent(int eventid)
{
return Authorized(authDto =>
{
var eventList = _eventService.GetPresentationByEvent(eventid);
return Ok(eventList)
})
}
我的理论是 return Authorized(authDto =>
持有一个线程直到它 returns,导致线程耗尽。
public async Task<IActionResult> GetPresentationByEvent(int eventid)
{
return Authorized(async authDto =>
{
Task<List<whatever>> eventList = _eventService.GetPresentationByEvent(eventid);
return Ok(eventList)
}
}
Authorized
是第三方库的一部分,所以我不能轻易测试这个。想知道这是否看起来像 problem/solution.
是的,async await 可以减少线程耗尽。简而言之,当您生成的任务多于 ThreadPool 可以处理的数量时,就会出现线程耗尽。
您可以在此处查看一些细微的细节:Thread starvation and queuing
你唯一需要记住的是你永远不应该在任务中阻塞。这意味着使用 async await 调用异步代码(永远不要在未完成的任务上使用 .Wait 或 .Result)。
如果您使用一些不使用异步等待模式的阻塞代码,您必须在专用线程(而不是任务线程队列)上生成它。
My theory is that return Authorized(authDto => holds a thread until it returns, leading to thread exhaustion.
是的。您可以通过查看其 return 值轻松判断方法是否同步。 IActionResult
不是等待类型,因此此方法将 运行 同步。
Authorized is part of a third-party library, so I can't test this easily. Would like to know if this looks like a likely problem/solution.
可能吧。这完全取决于 Authorized
是否可以处理异步委托。如果可以,那么这样的事情就可以了:
public async Task<IActionResult> GetPresentationByEvent(int eventid)
{
return Authorized(async authDto =>
{
Task<List<whatever>> eventList = _eventService.GetPresentationByEventAsync(eventid);
return Ok(await eventList);
});
}
注:
- 任务在传递给
Ok
或其他助手之前应该await
ed。 - 这引入了
GetPresentationByEventAsync
,假设您的数据访问代码可以异步。
由于使 GetPresentationByEvent
异步可能需要一些工作,因此值得在尝试此之前调查 Authorized
是否可以采用异步委托。
Does Using Async Await Avoid Thread Exhaustion?
是也不是。异步代码(包括 async
/await
)确实使用较少的线程,因为它避免了阻塞线程。但是,仍然有一个限制。线程耗尽仍然是可能的,因为异步代码需要一个空闲线程才能完成。使用异步代码,通常您可以在 运行 陷入线程耗尽等可伸缩性问题之前实现一个或两个更大的可伸缩性。
有关 async
ASP.NET 的更多概念信息,请参阅 this MSDN article。