【发布时间】:2020-12-15 11:57:29
【问题描述】:
我们的代码在返回时有时会出现问题
我有一个生产者/消费者应用程序,它启动多个消费者等待 BlockingCollection(命名队列)。
for (var i = 0; i < 10; i++)
{
var t = Task.Factory.StartNew(async () =>
{
try
{
await InboundQueue(stoppingToken.Value, queueProcessorId).ConfigureAwait(false);
}
catch (OperationCanceledException ocex)
{
}
catch (Exception ex)
{
}
}, TaskCreationOptions.LongRunning | TaskCreationOptions.DenyChildAttach);
在处理 processMessage 之前,每个消费者都在 TryTake 方法中被阻止。
if (!_queue.TryTake(out var message, timeToWait, cancellationToken))
{
..
await processMessage((T)message).ConfigureAwait(false);
..
}
在 processMessage 中,我们多次调用数据库执行 async/await,使用 async/await 调用 httpclient,甚至在某些情况下执行 Task.Run 来执行操作而不等待完成。
await 需要一些时间才能完成,这很奇怪。我们在 processMessage 中添加了一些额外的 ConfigureAwait(false) 代码,它在某些情况下有所帮助。仍然缓慢等待发生。
https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#avoid-using-taskrun-for-long-running-work-that-blocks-the-thread 阅读这篇文章,我们将更改代码以使用“新线程”而不是“Task.Factory.StartNew”。
1.因为我们将为运行消费者创建一个标准线程,所以我们是否需要在 processMesssage 方法中额外的 ConfigureAwait(false) 调用异步 httpclient 或数据库?
2.processMessage 有自己的线程,可以轻松同步。我们可以在请求异步调用的库上安全地执行 .Result 吗?
3.我们如何调试这种情况?注意:通过跟踪网络我们发现https调用和数据库调用总是很快的。
提前致谢。
【问题讨论】:
-
使用 PerfView 收集 ETW 跟踪并分析它以查看浪费时间的地方。
-
@DarkoZa .NET Async Tool for performance profiling 和 Concurrency Visualizer 可以成为你最好的朋友。
-
我们想分析生产环境,但那里没有 Visual Studio 安装。
标签: .net multithreading async-await