I'm trying to understand how Task.Run + Wait() + async + await work.
I have read this page: Understanding the use of Task.Run + Wait() + async + await used in one line but don't understand it quite well.
In my code, I receive events from Microsoft EventHub and process them using a class that implements IEventProcessor.
I call DoAnotherWork() method, which is an async method, in ConvertToEntity(), which is a sync method.
Since the method is async, I use Task.Run() and async to delegate. (i.e. Task.Run(async () => entities = await DoAnotherWork(entities)).Wait())
The code has been working for a while but now my team member removed Task.Run() and changed it to DoAnotherWork(entities).Result;. I'm not sure this won't cause deadlocks.
I haven't asked him why he changed it but this change got me thinking "Is my code fine? Why?".
My questions are:
* What is the difference between the two?
* Which code is appropriate and/or safe (= won't cause a deadlock)?
* In what situation is a deadlock caused if it is?
* Why Task.Run() resolve deadlock I had? (see below for detail)
Note: I'm using .NET Core 3.1.
Why I Use Task.Run()
My team had deadlock issues a few times when we used AbcAsync().Result or .Wait() (the method was called in a NET Core Web API methods and deadlocks occurred mostly when we ran unit tests that execute the method), so we've used Task.Run(async () => await AbcAsync()).Wait()/Result and we haven't seen any deadlock issues since then.
However, this page: https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d says that the delagation will cause a deadloock in certain conditions.
public class EventProcessor : IEventProcessor
{
public async Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
{
...
var result = await eventHandler.ProcessAsync(messages);
...
}
}
public Task async ProcessAsync(IEnumerable<EventData> messages)
{
...
var entities = ConvertToEntity(messages);
...
}
public List<Entity> ConvertToEntity(IEnumerable<EventData> messages)
{
var serializedMessages = Serialize(messages);
var entities = autoMapper.Map<Entity[]>(serializedMessages);
// Task.Run(async () => entities = await DoAnotherWork(entities)).Wait(); // before change
entities = DoAnotherWork(entities).Result; // after change
return entities;
}
public Task async Entity[] DoAnotherWork(Entity[] entities)
{
// Do stuff async
await DoMoreStuff(entities)...
}