[英]Deadlock when callin async method synchronously
显然,我在我的Execute
方法中创建了一个死锁,它基本上包装了一个异步实现。
public IEnumerable<IDataPoint> Execute(Guid batchId, Guid parameterId, DateTime startDateTime, DateTime endDateTime, int maxNumberOfDataPoints)
{
return this.ExecuteAsync(batchId, parameterId, startDateTime, endDateTime, maxNumberOfDataPoints)
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
}
public async Task<IEnumerable<IDataPoint>> ExecuteAsync(Guid batchId, Guid parameterId, DateTime startDateTime, DateTime endDateTime, int maxNumberOfDataPoints)
{
var foundDataPoints = new List<DataPoint>();
startDateTime = startDateTime.WithoutMilliseconds();
var firstDataPoint = await this.GetFirstDataPointBeforeDateTimeAsync(batchId, parameterId, startDateTime).ConfigureAwait(false);
var lastDataPoint = await this.GetFirstDataPointAfterDateTimeAsync(batchId, parameterId, endDateTime).ConfigureAwait(false);
var numberOfDatapointsToSubstract = firstDataPoint == null ? 0 : 1;
numberOfDatapointsToSubstract += lastDataPoint == null ? 0 : 1;
var dataPoints = await this.GetDataPointsBetweenDateTimesAsync(batchId, parameterId, startDateTime, endDateTime, maxNumberOfDataPoints - numberOfDatapointsToSubstract).ConfigureAwait(false);
if (firstDataPoint != null)
{
foundDataPoints.Add(firstDataPoint);
}
foundDataPoints.AddRange(dataPoints);
if (lastDataPoint != null)
{
foundDataPoints.Add(lastDataPoint);
}
return foundDataPoints.OrderBy(x => x.Timestamp);
}
虽然ExecuteAsync
工作得很好,但Execute
不会终止。 我不明白这个问题。 这似乎是一个僵局,但我不明白原因。
但是,像这样包装ExecuteAsync
是可行的:
return Task.Run(
async () =>
await this.ExecuteAsync(batchId, parameterId, startDateTime, endDateTime, maxNumberOfDataPoints)
.ConfigureAwait(false))
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
主要区别当然是ExecuteAsync
被包装在一个任务中。
更新:我认为ExecuteAsync
将始终在与调用者不同的线程上执行,并且通过显式禁用上下文同步我会很好,但显然我错了。
这并不能直接回答您“为什么会出现这种僵局”的问题,但这是值得考虑的事情,而且评论时间太长了。
如果您的目标是提供同步和异步方法,只是为了让使用您的代码的任何人都可以选择使用其中一种方法,那么您有两种选择:
别
正如您所发现的,像这样包装异步代码是有风险的,风险应该是:
被调用者知道。 那些使用Execute
方法的人可能不知道它包装了一个异步方法并且可能会导致问题。 (特别是如果这是在一个库中并且他们无法轻松访问源代码)
由调用者假定。 建议始终await
async
方法。 如果使用您的代码的人真的想同步等待它,那么风险就属于他们。 但是如果你自己提供一个同步包装器,他们会因为任何死锁而责备你。
所以你可以删除你的Execute
方法,人们可以处理它。
做不同的事
如果你真的想提供同步版本,你可以按照微软设定的模式。 它们有时确实提供同步和异步方法来做同样的事情,但它们的实现完全不同。 他们不只是包装异步方法。
你可以在他们的源代码中看到这一点。 例如,将File.InternalReadAllText()
(由File.ReadAllText()
使用)与File.InternalReadAllTextAsync()
(由File.ReadAllTextAsync()
使用)进行比较。
因此,编写一个不使用任何异步方法的同步版本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.