Reputation: 45
Let's assume I have these methods:
public async Task<Something> GetSomethingAsync()
{
var somethingService = new SomethingService();
return await service.GetAsync();
}
and
public Task<Something> GetSomethingAsync()
{
var somethingService = new SomethingService();
return service.GetAsync();
}
Both options compile and work the same way. Is there any best practise as to which option is better of if one is faster then the other?
Or is it just some syntactic sugar?
Upvotes: 4
Views: 1239
Reputation: 32445
In the first method compiler will generate "state machine" code around it and execution will be returned to the line return await service.GetAsync();
after task will be completed. Consider example below:
public async Task<Something> GetSomethingAsync()
{
var somethingService = new SomethingService();
// Here execution returns to the caller and returned back only when Task is completed.
Something value = await service.GetAsync();
DoSomething();
return value;
}
The line DoSomething();
will be executed only after service.GetAsync
task is completed.
Second approach simply starts execution of service.GetAsync
and return correspondent Task
to the caller without waiting for completion.
public Task<Something> GetSomethingAsync()
{
var somethingService = new SomethingService();
Task<Something> valueTask = service.GetAsync();
DoSomething();
return valueTask;
}
So in the example above DoSomething()
will be executed straight after line Task<Something> valueTask = service.GetAsync();
without waiting for completion of task.
Executing async
method on the another thread depend on the method itself.
If method execute IO
operation, then another thread will be only waste of the thread, which do nothing, only waiting for response. On my opinion async - await
are perfect approach for IO
operations.
If method GetAsync
contains for example Task.Run
then execution goes to the another thread fetched from thread pool.
Below is short example, not a good one, but it show the logic a tried to explain:
static async Task GetAsync()
{
for(int i = 0; i < 10; i++)
{
Console.WriteLine($"Iterate GetAsync: {i}");
await Task.Delay(500);
}
}
static Task GetSomethingAsync() => GetAsync();
static void Main(string[] args)
{
Task gettingSomethingTask = GetSomethingAsync();
Console.WriteLine("GetAsync Task returned");
Console.WriteLine("Start sleeping");
Thread.Sleep(3000);
Console.WriteLine("End sleeping");
Console.WriteLine("Before Task awaiting");
gettingSomethingTask.Wait();
Console.WriteLine("After Task awaited");
Console.ReadLine();
}
And output will be next:
Iterate GetAsync: 0
GetAsync Task returned
Start sleeping
Iterate GetAsync: 1
Iterate GetAsync: 2
Iterate GetAsync: 3
Iterate GetAsync: 4
Iterate GetAsync: 5
End sleeping
Before Task awaiting
Iterate GetAsync: 6
Iterate GetAsync: 7
Iterate GetAsync: 8
Iterate GetAsync: 9
After Task awaited
As you can see executing of GetAsync
starts straight after calling it.
If GetSomethingAsync()
will be changed to the:
static Task GetSomethingAsync() => new Task(async () => await GetAsync());
Where GetAsync
wrapped inside another Task, then GetAsync()
will not be executed at all and output will be:
GetAsync Task returned
Start sleeping
End sleeping
Before Task awaiting
After Task awaited
Of course you will need to remove line gettingSomethingTask.Wait();
, because then application just wait for task which not even started.
Upvotes: 2