简体   繁体   中英

Deadlock when callin async method synchronously

Obviously I created a deadlock here in my Execute Method which basically wraps an asynchronous implemtation.

 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);
}

While ExecuteAsync is working just fine Execute does not terminate. I don't get the problem. It seems to be a deadlock but I don't see the cause.

Wrapping ExecuteAsync like this works, though:

return Task.Run(
                    async () =>
                        await this.ExecuteAsync(batchId, parameterId, startDateTime, endDateTime, maxNumberOfDataPoints)
                            .ConfigureAwait(false))
                .ConfigureAwait(false)
                .GetAwaiter()
                .GetResult();

Main difference is of course that ExecuteAsync is being wrapped in a Task.

UPDATE: I thought that ExecuteAsync will be always executed on a different thread than the callers and by explicitley disabling context sync I would be fine but obviously I am wrong.

This doesn't directly answer your question of "why does this deadlock", but it's something to think about and it was getting too long for comment.

If your goal is to provide synchronous and asynchronous methods just to give anyone using your code the option of using either, you have two options:

Don't

As you have found, wrapping asynchronous code like this is risky, and the risk should be:

  1. Known by the caller. Those using the Execute method probably won't know that it wraps an asynchronous method and could cause problems. (especially if this is in a library and they don't have easy access to the source code)

  2. Assumed by the caller. The recommendation is always to await an async method. If someone using your code really wants to wait on it synchronously, then that risk belongs with them. But if you provide a synchronous wrapper yourself, they'll blame you for any deadlocks.

So you could just delete your Execute method and people can deal with it.

Do it differently

If you really want to provide a synchronous version, you can follow the pattern set by Microsoft. They do sometimes provide synchronous and asynchronous methods to do the same thing, but their implementations are completely different. They don't just wrap the asynchronous method.

You can see this in their source code. For example, compare File.InternalReadAllText() (which is used by File.ReadAllText() ) with File.InternalReadAllTextAsync() (which is used by File.ReadAllTextAsync() ).

So, write a synchronous version that doesn't use any asynchronous methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM