-2

I try to not create redundant Task objects in my code and I write Task returning functions instead of async Task functions where it is possible.

When it is necessary to save value returned by an async function, I am forced to make the function return async Task and call function with await.

Example:

async Task SomeWorkAsync()
{
   someGlobalVariable = await AnotherWorkAsync();
}

What I wrote instead:

Task SomeWorkAsync()
{
   var task = AnotherWorkAsync();
   someGlobalVariable = task.Result;
   return task;
}

But I am afraid that it will block calling thread as synchronous code does.

await SomeWorkAsync(); //main thread block

Is there another way to rewrite the code in example without wrapping a whole function with new Task as async keyword does?

  • task.Result does block the calling thread: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1.result?view=netframework-4.7.2 – Isma Jan 12 '19 at 17:39

3 Answers3

1

I try to not create redundant Task objects in my code and I write Task returning functions instead of async Task functions where it is possible.

That's not common nor the intended way of working with the TPL.

This is wrong:

Task SomeWorkAsync()
{
   var task = AnotherWorkAsync();
   someGlobalVariable = task.Result;
   return task;
}

You should be using

async Task<T> SomeWorkAsync()
{
   someGlobalVariable = await AnotherWorkAsync();
   return someGlobalVariable;
}

Only under strict circumstances should you use .Result to get the result of a Task.

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • Thanks for chiming in, i need to go to bed and your explanation is much better – TheGeneral Jan 12 '19 at 17:52
  • @TheGeneral No problem, have a nice sleep :) – Camilo Terevinto Jan 12 '19 at 17:52
  • you should never use .Result. Instead you should use .GetAwaiter().GetResult(). There are no circumstances where you can use .Result and cannot use .GetAwaiter().GetResult() – OlegI Jan 12 '19 at 17:55
  • @OlegI If you consider the warning of not using `.GetAwaiter()` in the summary of the function, since that's supposed to be used internally by the compiler, you should prefer using `.Result` – Camilo Terevinto Jan 12 '19 at 17:56
  • @CamiloTerevinto No. .Result will wrap all your exceptions into AggregateException, apart from that it behaves absolutely the same as .GetAwaiter().GetResult(). There are no use cases where you need to use .Result – OlegI Jan 12 '19 at 17:59
  • I read in some article that it is bad practice to add `async` keyword only for one call with `await` because it creates new Task and loads GC –  Jan 12 '19 at 18:01
  • @ДенисПеревозчиков And Stephen Cleary, one of the main developers, says not to worry about the extremely little overhead added. Please take the time to read: https://blog.stephencleary.com/2016/12/eliding-async-await.html there's just too many BS out there regarding the TPL. There are cases where async/await can be avoided, but not in the case in your question – Camilo Terevinto Jan 12 '19 at 18:03
  • @ДенисПеревозчиков you misunderstood `async` keyword. It does nothing but gives possibility to call awaitable method with `await` keyword – OlegI Jan 12 '19 at 18:03
  • 1
    @OlegI That's completely wrong. Using `await` adds a state machine in the generated code. That, while small, adds overhead – Camilo Terevinto Jan 12 '19 at 18:05
0

If you want to save your self a state machine, just call

public Task SomeWorkAsync()
{
   ...
   return AnotherWorkAsync();
}

Don't call Result, just return the task through without the async keyword in the method definition

In short, you are just returning a task, that can be awaited higher up

Update

Yes this does the trick if AnotherWorkAsync is async Task but in my case it is async Task<T>

public Task<MyAwesomeType> SomeWorkAsync()
{
   ...
   return AnotherWorkAsync();
}

Update 2

This is still not what I mean. Class which will call SomeWorkAsync doesn't know anything about private variable someGlobalVariable. It is necessary to get value and set this variable inside

public async Task SomeWorkAsync()
{
   someGlobalVariable = await AnotherWorkAsync();
}

If you need the result from the async method you will have to await it.

Try not to mix synchronous code and the async await pattern, which you are doing with Result, you can cause deadlocks... just let async propagate

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • Yes this does the trick if `AnotherWorkAsync` is `async Task` but in my case it is `async Task` and I need the result of `AnotherWorkAsync` –  Jan 12 '19 at 17:40
  • This is still not what I mean. Class which will call `SomeWorkAsync` doesn't know anything about private variable `someGlobalVariable`. It is necessary to get value and set this variable inside –  Jan 12 '19 at 17:46
  • well, now it is the same as I write in example :) It seems that there is no another way –  Jan 12 '19 at 18:11
  • @ДенисПеревозчиков it seems impossible what you ask. If you want not to block the thread there is no other way than to use `await` keyword. All other options would block the thread and run code synchronously – OlegI Jan 12 '19 at 18:14
0

To answer your question:

  1. Yes, calling .Result will block your thread.
  2. See my comment on why I think it's better to use await and not to return a task: https://stackoverflow.com/a/54211382/918058
haimb
  • 381
  • 3
  • 4