简体   繁体   中英

How to use async methods

I currently have problems using async methods the right way. I may missunderstood something...

In my current project i have some async methods which should run in parallel, but they don't. So i created a small example project to reproduce the error.

class Program
    {
        static void Main(string[] args)
        {
            TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
            taskAwaiter.GetResult();
        }

        private static async Task SomeParallelWork()
        {
            Console.WriteLine(DateTime.Now + ": Start Parallel Work");
            Task<string> task1 = HeavyDBWork(6000);
            Task<string> task2 = HeavyDBWork(3000);
            Task<string> task3 = HeavyDBWork(5000);
            Console.WriteLine(DateTime.Now + ": All Parallel Work started");
            await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
            Console.WriteLine(DateTime.Now + ": All Parallel Work done");
        }


        private static async Task<string> HeavyDBWork(int timeToWork)
        {
            Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);
            await Task.Delay(timeToWork);
            Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
            return "SomeReturnValue";
        }
    }

The output is as i would expect it to be:

20.03.2020 10:50:28: Start Parallel Work
20.03.2020 10:50:28: Start with heavy db work load: 6000
20.03.2020 10:50:28: Start with heavy db work load: 3000
20.03.2020 10:50:28: Start with heavy db work load: 5000
20.03.2020 10:50:28: All Parallel Work started
20.03.2020 10:50:31: End of heavy db work load: 3000
20.03.2020 10:50:33: End of heavy db work load: 5000
20.03.2020 10:50:34: End of heavy db work load: 6000
20.03.2020 10:50:34: All Parallel Work done

All Tasks are generated first and then running in parallel. But this is not what i experienced in my project...

so i extended my example with some more "real" work: A recursive fibonacci algorithm

class Program
    {
        static void Main(string[] args)
        {
            TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
            taskAwaiter.GetResult();
        }

        private static async Task SomeParallelWork()
        {
            Console.WriteLine(DateTime.Now + ": Start Parallel Work");
            Task<long> fibuTask = CPUWork(40);
            Task<string> task1 = HeavyDBWork(6000);
            Task<string> task2 = HeavyDBWork(3000);
            Task<string> task3 = HeavyDBWork(5000);
            Console.WriteLine(DateTime.Now + ": All Parallel Work started");
            await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
            await Task.WhenAll(new Task<long>[] { fibuTask });
            Console.WriteLine(DateTime.Now + ": All Parallel Work done");
        }


        private static async Task<string> HeavyDBWork(int timeToWork)
        {
            Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);
            await Task.Delay(timeToWork);
            Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
            return "SomeReturnValue";
        }

        private static async Task<long> CPUWork(int i)
        {
            Console.WriteLine(DateTime.Now + ": Start Fibu of " + i);
            long fibu = Fibu(i);
            Console.WriteLine(DateTime.Now + ": End Fibu of " + i);
            return await Task.FromResult<long>(fibu);
        }


        private static long Fibu(int i)
        {
            if(i==1||i==2)
            {
                return (long)1;
            } else
            {
                return Fibu(i-2) + Fibu(i - 1);
            }
        }
    }

Output:

20.03.2020 10:56:09: Start Parallel Work
20.03.2020 10:56:09: Start Fibu of 40
20.03.2020 10:56:10: End Fibu of 40
20.03.2020 10:56:10: Start with heavy db work load: 6000
20.03.2020 10:56:10: Start with heavy db work load: 3000
20.03.2020 10:56:10: Start with heavy db work load: 5000
20.03.2020 10:56:10: All Parallel Work started
20.03.2020 10:56:13: End of heavy db work load: 3000
20.03.2020 10:56:15: End of heavy db work load: 5000
20.03.2020 10:56:16: End of heavy db work load: 6000
20.03.2020 10:56:16: All Parallel Work done

Now the Fibunacci Sequence task is not just created first, it is some how await before the other tasks are created. I would expect the code to created all task and run them in parallel. What did i wrong?

Thanks for your answers!

Answer:

Thanks to Johnathan, Lasse and Theodor i was able to fix my code example.

So the new example executes three fibunacci algorithms asynchronously.

class Program
    {
        static void Main(string[] args)
        {
            TaskAwaiter taskAwaiter = SomeParallelWork().GetAwaiter();
            taskAwaiter.GetResult();
        }

        private static async Task SomeParallelWork()
        {
            Console.WriteLine(DateTime.Now + ": Start Parallel Work");
            Task<long> fibuTask1 = CPUWork(45);
            Task<long> fibuTask2 = CPUWork(40);
            Task<long> fibuTask3 = CPUWork(40);
            Console.WriteLine(DateTime.Now + ": All Parallel Work started");

            //await Task.WhenAll(new Task<string>[] { task1, task2, task3 });
            await Task.WhenAll(new Task<long>[] { fibuTask1, fibuTask2, fibuTask3 });
            Console.WriteLine(DateTime.Now + ": All Parallel Work done");
        }


        private static async Task<string> HeavyDBWork(int timeToWork)
        {
            Console.WriteLine(DateTime.Now + ": Start with heavy db work load: " + timeToWork);

            await Task.Delay(timeToWork);
            Console.WriteLine(DateTime.Now + ": End of heavy db work load: " + timeToWork);
            return "SomeReturnValue";
        }

        private static async Task<long> CPUWork(int i)
        {
            Console.WriteLine(DateTime.Now + ": Start Fibu of " + i);

            Func<long> fibuFunc = () => Fibu(i);
            Task<long> fibuTask = Task.Run(fibuFunc);

            long fibu = await fibuTask;


            Console.WriteLine(DateTime.Now + ": End Fibu of " + i);
            return fibu;
        }


        private static long Fibu(int i)
        {
            if(i==1||i==2)
            {
                return (long)1;
            } else
            {
                return Fibu(i-2) + Fibu(i - 1);
            }
        }
    }

Output:

20.03.2020 11:59:39: Start Parallel Work
20.03.2020 11:59:39: Start Fibu of 45
20.03.2020 11:59:39: Start Fibu of 40
20.03.2020 11:59:39: Start Fibu of 40
20.03.2020 11:59:39: All Parallel Work started
20.03.2020 11:59:41: End Fibu of 40
20.03.2020 11:59:41: End Fibu of 40
20.03.2020 11:59:53: End Fibu of 45
20.03.2020 11:59:53: All Parallel Work done

Your CPUWork method will actually run synchronously, even though it is declared as async .

Async methods only return a Task when the first await is encountered, and Task.FromResult just wraps a value in an already completed Task , so using await will just unwrap the value straight away and return it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM