await/async 基本使用

(1)async和await配套使用,返回值为void

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Program pr = new Program();
            Console.WriteLine("主线程开始---------------");
            pr.TestVoidAsync();
            Console.WriteLine("主线程结束---------------");
            Console.ReadLine();

        }

        private async void TestVoidAsync()
        {
            Console.WriteLine("开始执行TestVoidAsync方法");
            Task task = new Task(() =>
            {
                Console.WriteLine("开始子线程耗时操作");
                Thread.Sleep(3000);
                Console.WriteLine("结束子线程耗时操作");

            });
            task.Start();
            await task;
            Console.WriteLine("await关键字后面的内容 1");
            Console.WriteLine("await关键字后面的内容 2");
        }
     }
}

我们会发现,使用await后,执行到await,主线程就是返回去做自己的事情,而await后面的内容将会在子线程执行完成后再继续完成。

await的作用和ContinueWith的作用类似,可以在上一任务以后接下一个任务,并且不会阻塞主线程。

(2)async和await配套使用,返回值Task

  • async Task 等效于 async void
  • 但是返回Task ,可以使用await,并且可以与Task.WhenAny, Task.WhenAll ContinueWith等组合使用,Void不可以
  • 建议使用async Task 这种形式(除事件处理程序外)

 写法与async void 相比,没有什么太大的不一样,只是将void ,更换为Task而已,但是返回Task,可以使用await 以及一些Task的方法,如Task.WhenAny, Task.WhenAll ContinueWith等,更有利于后续逻辑的扩展。

如:我们可以在返回Task的方法执行完后使用ContinueWith 再接一个执行任务。

        public void TestTask()
        {            
            var task = TestTaskAsync();            
            task.ContinueWith((t) =>
            {
                Debug.WriteLine("这里是接着TestTaskAsync方法的执行代码。。。");
            });
        }

在Main函数中调用 TestTask()即可;

(3)async和await配套使用,返回值Task<T>

  • 如果async和await配套使用的时候,需要返回值,则必须通过Task<T>的形式返回值
  • 如果不是,编译器会操作,如下图所示
 private async Task<int> TestTaskIntAsync()
        {
            Debug.WriteLine("开始执行TestTaskAsync方法");
            int result = 0;
            Task task = new Task(() =>
            {
                Debug.WriteLine("开始子线程耗时操作");
                Thread.Sleep(4000);
                Debug.WriteLine("结束子线程耗时操作");
                result = 10;
            });
            task.Start();
            await task;
            Debug.WriteLine("await关键字后面的内容 1");
            Debug.WriteLine("await关键字后面的内容 2");
            return result;
        }

 该方法与我们平常返回一个int值的方法没什么太大区别,不过是多了async 和 await ,那么下面将演示如何取出异步方法的返回值。

        //方法一:使用ContinueWith
        private void button4_Click(object sender, EventArgs e)
        {
            Task<int> task = TestTaskIntAsync();
            task.ContinueWith((t) =>
            {    
                //不能使用Sleep()来阻碍线程,会取不到值
                //Thread.Sleep(1000);
                Debug.WriteLine($"TestTaskIntAsync的返回值是:{t.Result.ToString()}");
            });
        }
        
        //方法二:使用await
        private async void button4_Click(object sender, EventArgs e)
        {
            Task<int> task = TestTaskIntAsync();
            await task;
            Debug.WriteLine($"TestTaskIntAsync的返回值是:{task.Result.ToString()}");
        }

(4)不使用async和await,返回值Task<T>

  • 之所以列举出来是需要注意区别使用async和await 返回的Task<T> 和不使用async和await 返回Task<T>
        private Task<int> TestTaskInt()
        {
            Debug.WriteLine("开始执行TestTaskAsync方法");
            Task<int> task = new Task<int>(() =>
            {
                Debug.WriteLine("开始子线程耗时操作");
                Thread.Sleep(4000);
                Debug.WriteLine("结束子线程耗时操作");
                int result = 10;//模拟有返回值
                return result;
            });
            task.Start();
            return task;
        }

		//调用,获取返回值
        private void button4_Click(object sender, EventArgs e)
        {
            var task = TestTaskInt();
            task.ContinueWith((t)=> 
            {
                Debug.WriteLine(t.Result.ToString());
            });
        }

 (5)使用Async和Await实现多任务顺序执行且不阻塞

1.同步执行

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            PourOJ();
            PourCoffee();
            ToastBread();
            FryBacon();
            FryEggs();
            Console.WriteLine("早餐已经做完!");
            stopwatch.Stop();
            Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
            Console.ReadLine();
        }

        //倒橙汁
        private static void PourOJ()
        {
            Thread.Sleep(1000);
            Console.WriteLine("倒一杯橙汁");
        }

        //烤面包
        private static void ToastBread()
        {
            Console.WriteLine("开始烤面包");
            Thread.Sleep(3000);
            Console.WriteLine("烤面包好了");

        }

        //煎培根
        private static void FryBacon()
        {
            Console.WriteLine("开始煎培根");
            Thread.Sleep(6000);
            Console.WriteLine("培根煎好了");
        }
        //煎鸡蛋
        private static void FryEggs()
        {
            Console.WriteLine("开始煎鸡蛋");
            Thread.Sleep(6000);
            Console.WriteLine("鸡蛋好了");
        }

        //倒咖啡
        private static void PourCoffee()
        {
            Thread.Sleep(1000);
            Console.WriteLine("倒咖啡");
        }
    }
}

2、异步并行

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Test();
            Console.ReadLine();
        }

        private static void Test()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            List<Task> tasks = new List<Task>() { PourOJ(), ToastBread(), FryBacon(), FryEggs(), PourCoffee() };
            Task.WhenAll(tasks).ContinueWith((t)=> 
            {
                Console.WriteLine("早餐已经做完!");
                stopwatch.Stop();
                Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
            });
        }

        //倒橙汁
        private static async Task PourOJ()
        {
            await Task.Delay(1000);
            Console.WriteLine("倒一杯橙汁");
        }

        //烤面包
        private static async Task ToastBread()
        {
            Console.WriteLine("开始烤面包");
            await Task.Delay(3000);
            Console.WriteLine("烤面包好了");

        }

        //煎培根
        private static async Task FryBacon()
        {
            Console.WriteLine("开始煎培根");
            await Task.Delay(6000);
            Console.WriteLine("培根煎好了");
        }
        //煎鸡蛋
        private static async Task FryEggs()
        {
            Console.WriteLine("开始煎鸡蛋");
            await Task.Delay(6000);
            Console.WriteLine("鸡蛋好了");
        }

        //倒咖啡
        private static async Task PourCoffee()
        {
            await Task.Delay(1000);
            Console.WriteLine("倒咖啡");
        }
    }
}

3、并行且可指定顺序执行

        private static async void Test()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            await PourOJ();
            await PourCoffee();            
            List<Task> tasks = new List<Task>() { ToastBread(), FryBacon(), FryEggs() };
            await Task.WhenAll(tasks);
            Console.WriteLine("早餐已经做完!");
            stopwatch.Stop();
            Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
        }

猜你喜欢

转载自blog.csdn.net/h_ppap/article/details/128684506