Search code examples
c#asynchronousdeadlock

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.


Solution

  • 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