簡體   English   中英

同步調用異步方法時出現死鎖

[英]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將始終在與調用者不同的線程上執行,並且通過顯式禁用上下文同步我會很好,但顯然我錯了。

這並不能直接回答您“為什么會出現這種僵局”的問題,但這是值得考慮的事情,而且評論時間太長了。

如果您的目標是提供同步和異步方法,只是為了讓使用您的代碼的任何人都可以選擇使用其中一種方法,那么您有兩種選擇:

正如您所發現的,像這樣包裝異步代碼是有風險的,風險應該是:

  1. 被調用者知道。 那些使用Execute方法的人可能不知道它包裝了一個異步方法並且可能會導致問題。 (特別是如果這是在一個庫中並且他們無法輕松訪問源代碼)

  2. 由調用者假定。 建議始終await async方法。 如果使用您的代碼的人真的想同步等待它,那么風險就屬於他們。 但是如果你自己提供一個同步包裝器,他們會因為任何死鎖而責備你。

所以你可以刪除你的Execute方法,人們可以處理它。

做不同的事

如果你真的想提供同步版本,你可以按照微軟設定的模式。 它們有時確實提供同步和異步方法來做同樣的事情,但它們的實現完全不同。 他們不只是包裝異步方法。

你可以在他們的源代碼中看到這一點。 例如,將File.InternalReadAllText() (由File.ReadAllText()使用)與File.InternalReadAllTextAsync() (由File.ReadAllTextAsync()使用)進行比較。

因此,編寫一個不使用任何異步方法的同步版本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM