Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between Foo().Result and Task.Run(() => Foo()).Result in C#?

In C# what is the difference between these two statements? If I use the first one in my constructor in my test classes I get a deadlock, or something similar, and the tests never finish. With the second one the code works.

// Deadlock.
var r = MyMethod().Result;

// Works.
var r = Task.Run(() => MyMethod()).Result;

Update: There is a bit more context in this commit: https://github.com/webCRMdotcom/erp-integrations/pull/92/commits/dd8af89899ce1de837ef6e34f0688a685a5cea3b.

like image 702
Jan Aagaard Avatar asked Jul 12 '18 06:07

Jan Aagaard


People also ask

What is the difference between Task run () and Taskfactory StartNew () methods?

Task. Run(action) internally uses the default TaskScheduler , which means it always offloads a task to the thread pool. StartNew(action) , on the other hand, uses the scheduler of the current thread which may not use thread pool at all!

What is the difference between Task run and async await?

First of all, when you call an async method with Task. Run() , it will not pass on the current synchronization context to the async method. That means that when the async method continues after an await , it will not continue on the main thread in a WinForms application (for example).

What is the difference between async await and Task in C#?

async, await, and TaskThe await keyword waits for the async method until it returns a value. So the main application thread stops there until it receives a return value. The Task class represents an asynchronous operation and Task<TResult> generic class represents an operation that can return a value.

What is GetAwaiter () GetResult ()?

GetAwaiter(). GetResult()" is presented as a good way to replace ". Result" and ". Wait()" when we can't use async/await.


1 Answers

The difference is the starting thread context.

Here a simple sample

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        string r;
        OutputThreadInfo("Main");
        r = MyMethod().Result;
        r = Task.Run( () => MyMethod() ).Result;
    }

    public static async Task<string> MyMethod()
    {
        OutputThreadInfo("MyMethod");
        await Task.Delay(50);
        return "finished";
    }

    private static void OutputThreadInfo(string context)
    {
        Console.WriteLine("{0} {1}",context,System.Threading.Thread.CurrentThread.ManagedThreadId);
    }
}

.net fiddle

which will output

Main 32
MyMethod 32
MyMethod 63

The first call of MyMethod will start at the same thread as Main and if started from a thread with a synchronization context it will block.

The second call of MyMethod will start from a different thread (worker thread from thread pool) as Main which does not have a synchronization context and therefor will not block.

PS You should keep in mind that Console applications do not have a synchronization context as default but WinForms, WPF, UWP application do have and so will behave somehow different on async/await

like image 135
Sir Rufo Avatar answered Oct 01 '22 23:10

Sir Rufo