1

I have an async call and I wrapped it inside a Task.Run to run it in another thread. Will the organizations assignment and all subsequent code halt until it returns and get the Result? Or will it continue and sometimes generate a null reference exception once it reaches the foreach? In my tests it never throws errors, but maybe I was just lucky.

        IDictionary<string, organization> organizations = Task.Run(() => this.GetOrganizationsAsync()).Result;

...lines of code

        foreach (var organization in organizations)
        {
user33276346
  • 1,501
  • 1
  • 19
  • 38
  • 2
    What benefit are you expecting by running `GetOrgnaizationsAsync` on a separate thread? If it is a true async operation (ends up waiting on network, disk, database, etc) then you can call `GetOrgnaizationsAsync`, store the task, and then when you need the result call `await`. This will allow the thread to start the async operation, continue doing all other work required, and when you need the results of the operation to wait (but not block the thread) for the results. – Jeffrey Parks Nov 22 '19 at 17:05
  • 1
    Result is a blocking call and can cause deadlocks. You should avoid it. – William Xifaras Nov 22 '19 at 17:07
  • 1
    **Never do this**. If you intend the workflow to run synchronously then *do not run it asynchronously in the first place*. Don't run it asynchronously and then dangerously introduce a synchronous wait! – Eric Lippert Nov 22 '19 at 18:22
  • 1
    The correct asynchronous multithreaded workflow is workflow four: hire a worker to mow your lawn, and while you are *asynchronously waiting*, find something else to do, which could include finding the mower. Keep finding other tasks to do until the lawn is mowed, and then eat lunch. **Asynchrony is there to be used; use it**. – Eric Lippert Nov 22 '19 at 18:25

2 Answers2

3

The Remarks section of the documentation for Task.Result says:

Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.

So yeah, it won't proceed until GetOrganizationsAsync() is completed. But two things:

  1. There's no reason to use Task.Run. You use that when you want something to move to another thread so the current thread can continue doing other things. But then you're blocking the current thread until it's done anyway. So Task.Run is just adding overhead for no reason here.

  2. Blocking on an asynchronous operation can also cause problems with deadlocks: Don't Block on Async Code

Any reason you can't just make your method async and use await GetOrganizationsAsync()? That's far more desirable, since you won't be blocking any threads.

Microsoft has a series of well-written articles on Asynchronous programming with async and await that are worth reading.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
0

Calling .Result is a bad idea because it can sometimes cause your code to lock up--I suggest you do some reading to convince yourself that's the case.

The best way is to either call await on GetOrganizationsAsync and make the method that's executing it asynchronous. That may mean that asyc methods begin to propagate throughout your code, but that's just how the cookie crumbles. There are ways to do it that avoids having to do that, and I have seen it written in production code that mostly works, but I don't recommend it.

Here's more reading on the subject: Is Task.Result the same as .GetAwaiter.GetResult()?

Slothario
  • 2,830
  • 3
  • 31
  • 47