[英]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.