Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread.Sleep in Task.Run

I have been trying to get my head around C#'s new async/await and Task.Run functionality recently. In doing so I wrote some simple test code that writes to the console so that I can see in what order things happen in, throwing in a Thread.Sleep here and there to make sure things really happens in the order I expected.

Here is one of my tests

[Test]
public void TaskRun()
{
    Console.WriteLine("Before");
    Task.Run(() => Console.WriteLine(_terminator.IWillBeBack()));
    Console.WriteLine("After");
}

with the following Terminator class:

public class Terminator
{
    public string IWillBeBack()
    {
        return "I will be back";
    }
}

From this I expected the result to most likely be Before, After, and then I will be back. This is indeed what happens. Then I make a change to the IWillBeBack-method to allow it to sleep for 3 seconds. The code for this:

public class Terminator
{
    public string IWillBeBack()
    {
        Thread.Sleep(3000);
        return "I will be back";
    }
}

I expected the result to still be Before, After, and then after 3 seconds again I will be back. This is not what happens though. I instead get Before and After, but never I will be back.

Why is this?

When I debug it clearly goes through the code, sleeping and returning. I don't need Thread.Sleep in this way in any production code, but I would like to have a vague understanding of why I will be back is not written to the console in the second case.

like image 426
Halvard Avatar asked Jan 15 '23 23:01

Halvard


2 Answers

Your test is completing before it tries to print "I will be back". You're not doing anything to wait until that's finished. Depending on the test runner, however it's redirecting Console.WriteLine may have been disconnected as soon as the test has finished.

If you want to see it finish, change your test to:

[Test]
public void TaskRun()
{
    Console.WriteLine("Before");
    var task = Task.Run(() => Console.WriteLine(_terminator.IWillBeBack()));
    Console.WriteLine("After");
    task.Wait();
}
like image 126
Jon Skeet Avatar answered Jan 25 '23 23:01

Jon Skeet


If you use the MS Test framework in VS 2012 you can also write the test like this

[TestMethod]
public async Task TaskRun()
{
    Console.WriteLine("Before");
    Task t = Task.Run(() => Console.WriteLine(IWillBeBack()));
    Console.WriteLine("After");
    await t;
}

private string IWillBeBack()
{
    Thread.Sleep(3000);
    return "I will be back";
}
like image 29
softveda Avatar answered Jan 25 '23 23:01

softveda