c#Task异步的简单使用

四个相关概念:

同步(Synchronous)
异步( Asynchronous)
阻塞( Blocking )
非阻塞( Nonblocking)

通俗理解 (易懂)

同步异步 指的是在客户端

同步意味着 客户端提出了一个请求以后,在回应之前只能等待

异步意味着 客户端提出一个请求以后,还可以继续提其他请求

阻塞非阻塞 指的是服务器端

阻塞意味着 服务器接受一个请求后,在返回结果以前不能接受其他请求

非阻塞意味着 服务器接受一个请求后,尽管没有返回结果,还是可以继续接受其他请求

所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由调用者主动等待这个调用的结果。

而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。

举个通俗的例子:

同步通信机制
你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。

异步通信机制

书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调

2. 阻塞与非阻塞:关注的是程序在等待调用结果(消息,返回值)时的状态.

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

还是上面的例子,
你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。

网上同步与异步比较经典的例子

   static void Main(string[] args)
        {
            Console.WriteLine("********同步调用开始**********");
            int result = Add(1, 2);
            Console.WriteLine("同步调用完毕,执行结果为:" + result);

            Console.WriteLine("********异步调用开始**********");
            SynAdd(1, 2, (r) => {
                Console.WriteLine("异步调用完毕,执行结果为:" + r);
            });
            Console.WriteLine("-------完毕!----------");
            Console.ReadLine();
        }

        /// 
        /// 同步方法
        /// 
        /// 
        /// 
        /// 
        static int Add(int a, int b)
        {
            Thread.Sleep(5000);
            return a + b;
        }

        /// 
        /// 异步调用
        /// 
        /// 
        /// 
        /// 委托对象
        static void SynAdd(int a, int b, Action<int> callback)
        {
            Func<int> func = () =>
            {
                Thread.Sleep(5000);
                return a + b;
            };//声明异步方法实现方式
            func.BeginInvoke((ar) =>
            {
                var result = func.EndInvoke(ar);//调用完毕执行的结果
                callback.Invoke(result);//委托执行,回传结果值
            }, null);
        }          

c#Task异步的简单使用_第1张图片

异步实例

 static void Main(string[] args)
        {
            //第一种
            var task = new Task(() =>
                {
                    Console.WriteLine("任务开始....");

                    Console.WriteLine("任务结束....");
                });
            task.Start();
            Console.WriteLine("主线程开始....");

            Console.WriteLine("主线程结束....");

            //第二种
            new Task(() =>
            {
                Console.WriteLine("任务开始2....");

                Console.WriteLine("任务结束2....");
            }).Start();
            Console.WriteLine("主线程开始2....");

            Console.WriteLine("主线程结束2....");

          

            //第三种
            new Task((i)=> {
                Console.WriteLine("任务开始3....");
                for(int j = 0;j<(int)i;j++)
                {
                    Console.WriteLine(j.ToString());
                }
                Console.WriteLine("任务结束3....");
            },10).Start();
            Console.WriteLine("主线程开始3....");

            Console.WriteLine("主线程结束3....");

            //第四种
            new Task(StartCode,10).Start();
            Console.WriteLine("主线程开始4....");

            Console.WriteLine("主线程结束4....");
            Console.ReadLine();
        }
        private static void StartCode(object i)//
        {
            Console.WriteLine("任务开始4....");
            Console.WriteLine("开始执行4子线程...{0}",i);

            Console.WriteLine("任务结束4....");

        }

结果c#Task异步的简单使用_第2张图片

Task.Run和Task.Factory.StartNew

Task.Run 是在 dotnet framework 4.5 之后才可以使用,但是 Task.Factory.StartNew 可以使用比 Task.Run 更多的参数,可以做到更多的定制。可以认为 Task.Run 是简化的 Task.Factory.StartNew 的使用,除了需要指定一个线程是长时间占用的,否则就使用 Task.Run。

 static void Main(string[] args)
        {
            //第一种
            var task = new Task( () =>
                {
                     Console.WriteLine("任务开始....");
                    Thread.Sleep(100);
                    Console.WriteLine("任务结束....");
                });
            task.Start();
            Console.WriteLine("主线程开始....");

            Console.WriteLine("主线程结束....");

            //第二种
            Task.Run(() => {
                Console.WriteLine("任务开始2....");

                Console.WriteLine("任务结束2....");
            });
            Console.WriteLine("主线程开始2....");

            Console.WriteLine("主线程结束2....");
            

            Task.Factory.StartNew(() =>
            {
                try//异常是在里面抛出的否则就是错误写法没有作用。
                {
                    Console.WriteLine("进行 线程" + Thread.CurrentThread.ManagedThreadId);
                }
                catch
                {
                    throw new Exception("抛出异常");
                }
            }, TaskCreationOptions.LongRunning);//长时间运行


            Console.Read();

        }
 

结果
c#Task异步的简单使用_第3张图片

Task.wait和Task.waitall(

Task.Wait(参数):
参数=空: 无限等待下去,知道该线程结束
参数=millisecondTimeout; 等待指定的时间)

   //第一种
            var task = new Task( () =>
                {
                     Console.WriteLine("任务开始....");
                    Thread.Sleep(100);
                    Console.WriteLine("任务结束....");
                });
            task.Start();
            Console.WriteLine("主线程开始....");
            
            Console.WriteLine("主线程结束....");

            //第二种
            var task2 = new Task(() =>
            {
                Console.WriteLine("任务开始2....");
                Thread.Sleep(100);
                Console.WriteLine("任务结束2....");
            });
            task2.Start();
            Console.WriteLine("主线程开始2....");
            task2.Wait(10);//阻塞时间 不用等其它完成,只等时间
            
            Console.WriteLine("主线程结束2....");


            //第三种
            var task3 = new Task(() =>
            {
                Console.WriteLine("任务开始3....");
                Thread.Sleep(100);
                Console.WriteLine("任务结束3....");
            });
            task3.Start();
            Console.WriteLine("主线程开始3....");
            task3.Wait();//这里相当于阻塞,要等其它完成才行
            Console.WriteLine("主线程结束3....");

结果
c#Task异步的简单使用_第4张图片
Task.waitall 和WaitAny参数而是一个常规方法体

  static void Main(string[] args)
        {
            //第一种
            var task = new Task( () =>
                {
                     Console.WriteLine("任务开始....");
                    Thread.Sleep(100);
                    Console.WriteLine("任务结束....");
                });
            task.Start();
            Console.WriteLine("主线程开始....");
            
            Console.WriteLine("主线程结束....");

            //第二种
            var task2 = new Task(() =>
            {
                Console.WriteLine("任务开始2....");
                Thread.Sleep(100);
                Console.WriteLine("任务结束2....");
            });
            task2.Start();
            Console.WriteLine("主线程开始2....");

            
            Console.WriteLine("主线程结束2....");


            //第三种
            var task3 = new Task(() =>
            {
                Console.WriteLine("任务开始3....");
                Thread.Sleep(100);
                Console.WriteLine("任务结束3....");
            });
            task3.Start();
            Console.WriteLine("主线程开始3....");
            Console.WriteLine("主线程结束3....");
            Task.WaitAny(task, task2, task3);
            Console.WriteLine("WaitAny");
            Task.WaitAll(task, task2, task3);
            Console.WriteLine("WaitAll");


            Console.Read();

        }

结果
c#Task异步的简单使用_第5张图片
Task.Delay()和Thread.Sleep()最大的区别是Task.Delay()旨在异步运行,在同步代码中使用Task.Delay()是没有意义的;在异步代码中使用Thread.Sleep()是一个非常糟糕的主意。通常使用await关键字调用Task.Delay()。可以把前面的sleep改成task。delay。。。。

你可能感兴趣的:(c#)