Translate

Saturday 6 October 2012

Thread.Sleep is not the same as await

Note: Since Blogger eats up less than and greater than symbols, please replace async Task with Task of int as in generic types.

The most common mistake that many make about asynchronous processing is to think that Thread.Sleep means asynchronous. To demonstrate this is the below code, which is a "buggy" code because of the Thread.Sleep call.


// The code

using System.Threading.Tasks;

namespace Net45.UnitTests.Samples.Jv
{
    public class ClassUnderTest
    {
        public static int? taskId;
        public static string taskName;
        public static int result;
        public async Task "less than" int "greater than" AddWithTask(int a, int b)
        {
            await Task.Factory.StartNew(async () =>
            {
                taskName = "AddWithTask";
                taskId = Task.CurrentId;
                result = await add(a, b);
            });
            return result;
        }
        public async Task "less than" int "greater than"add(int a, int b)
        {
            int x = 0;
             Task.Factory.StartNew( ()=>            
            {
            x = a + b;
            taskId = Task.CurrentId;
            System.Threading.Thread.Sleep(20); // Without using this statement you will see the tests failing (as shown in point 5 in the previous post), the synchronous task continues its execution giving the impression that using Thread.Sleep() makes for asynchronous processing (because if you use the  code without a test, the code will compile and execute correctly but not with the expected result), Await makes the caller receive the callback result and not Thread.Sleep. 
To see it in action, modify the async method above to look like this
public async Task 
"less than" int "greater than" add(int a, int b)
        {
            int x = 0;
            await Task.Factory.StartNew( ()=>            
            {
            x = a + b;
            taskId = Task.CurrentId;
            //System.Threading.Thread.Sleep(20);
            });
            return x;
        }

            });
            return x;
        }
        public async Task "less than" int "greater than"returnAdditionResult(int a, int b)
        {
            int x = 0;
            x = await add(a, b);
            return a+b;
        }

    }
}


// The test class

using System;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
namespace Net45.UnitTests.Samples.Jv
{
    [TestFixture]
    public class AnthonySteeleClass
    {
        ClassUnderTest cutHandle = new ClassUnderTest();
        int? taskId;
        [SetUp]
        public void init()
        {         
            Console.WriteLine("Value of x is {0}", ClassUnderTest.result);
            Console.WriteLine(ClassUnderTest.taskName + " id is " + taskId); // To be used by yourself as you want to.
            Console.WriteLine("add method task id {0}",ClassUnderTest.taskId);
        }
        [Test]
        public async void TestAdd()
        {
            int answer = await cutHandle.AddWithTask(40, 2);
            Assert.That(answer, Is.EqualTo(42));
        }        
        [Test]
        public async void TestAsyncLambdaTask()
        {
            int answer = await cutHandle.AddWithTask(40, 2);
            Assert.AreEqual(42, answer);
        }
    }
}

No comments: