• C# Task中的Func, Action, Async与Await的使用


    在说Asnc和Await之前,先说明一下Func和Action委托, Task任务的基础的用法

    1. Func

    Func是一种委托,这是在3.5里面新增的,2.0里面我们使用委托是用Delegate,Func位于System.Core命名空间下,使用委托可以提升效率,例如在反射中使用就可以弥补反射所损失的性能。

    Action<T>和Func<T,TResult>的功能是一样的,只是Action<T>没有返类型,

    Func<T,T,Result>:有参数,有返回类型
    Action,则既没有返回也没有参数,

    Func<T,TResult> 
    的表现形式分为以下几种:

    1。Func<T,TResult>
    2。Func<T,T1,TResult>
    3。Func<T,T1,T2,TResult>
    4。Func<T,T1,T2,T3,TResult>
    5。Func<T,T1,T2,T3,T4,TResult>

    分别说一下各个参数的意义,TResult表示 
    委托所返回值 所代表的类型, T,T1,T2,T3,T4表示委托所调用的方法的参数类型,

    以下是使用示例:

    复制代码
     1 Func<int, bool> myFunc = null;//全部变量
     2 
     3 myFunc = x => CheckIsInt32(x); 
     4 //给委托封装方法的地方 使用了Lambda表达式
     5 
     6 private bool CheckIsInt32(int pars)//被封装的方法
     7 {
     8   return pars == 5;
     9 }
    10 
    11 bool ok = myFunc(5);//调用委托
    复制代码


    MSDN:http://msdn.microsoft.com/zh-cn/library/bb534303(VS.95).aspx

    2. Action

    但是如果我们需要所封装的方法不返回值,增么办呢?就使用Action!

    可以使用
    Action<T1, T2, T3, T4>委托以参数形式传递方法,而不用显式声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应。也就是说,封装的方法必须具有四个均通过值传递给它的参数,并且不能返回值。(在 C# 中,该方法必须返回 void。在 Visual Basic 中,必须通过 Sub…End Sub 结构来定义它。)通常,这种方法用于执行某个操作。

    使用方法和Func类似!

    Action:既没有返回,也没有参数,使用方式如下:

    1 Action action = null;//定义action
    2 
    3 action =  CheckIsVoid;//封装方法,只需要方法的名字
    4 
    5 action();//调用

    MSDN:http://msdn.microsoft.com/zh-cn/library/bb548654(VS.95).aspx

    总结:

    使用Func<T,TResult>和Action<T>,Action而不使用Delegate其实都是为了简化代码,使用更少的代码达到相同的效果,不需要我们显示的声明一个委托。

    Func<T,TResult>的最后一个参数始终是返回类型,而Action<T>是没有返回类型的,而Action是没有返回类型和参数输入的.

    3. Task

    使用 Async 和 Await 的异步编程(msdn的好文章) :  https://msdn.microsoft.com/zh-cn/library/hh191443(v=vs.120)

    Task基本使用: C# 线程知识--使用Task执行异步操作

    Task和await结合返回值见: .NET(C#):await返回Task的async方法

    Task深入了解见: C# Task的使用

    总结: Task提供一种新的类似多线程的多任务的用法, 达到使用线程的效果,但具体怎么分配线程由.net底层控制,这样性能好,效率也高,我们只需要专注业务逻辑, 同时具备以前线程不具备的返回值的功能(可以通过回调事件来处理),而在Task中只是简单的使用await来使用, await的task相当于同步的调用task, 同时会有返回值,只是在书写方面需要注意async, task,func, action等等关键字的使用,新手可能很困惑, 下面的例子就是一个简单的task使用例子,新手注意注释!!!

    复制代码
     1 static void Main(string[] args)
     2 {
     3     //异步方法, 当中使用await可以执行task异步任务,否则当作同步执行
     4     test();
     5     //其次输出,因为异步进入task任务了,就同步执行当前线程下面的代码
     6     log("Main:调用test后");
     7     Thread.Sleep(Timeout.Infinite); 
     8 }
     9 
    10 //Main方法不允许加async,所以我们用这个方法使用await
    11 static async void test()
    12 {
    13     //最先输出,还没有进入task
    14     log("test: await之前");
    15     // await后的内容会被加在目标doo的Task的后面,然后test马上返回,而doo则是进入了另一个任务执行了
    16     log("doo的Task的结果: " + await doo());
    17     // 会等到上面await执行的任务完成后才会执行当前代码
    18     log("test: await之后");
    19 }
    20 //返回Task的async方法, 一个标准的带返回值的异步task任务方法
    21 static async Task<int> doo()
    22 {
    23     // 简单的说, async中使用await就是异步中以同步方式执行Task任务的方法,task任务一个接一个执行.
    24     var res1 = await Task.Run(() => { Thread.Sleep(1000); log("Awaited Task1 执行"); return 1; });
    25     var res2 = await Task.Run(() => { Thread.Sleep(1000); log("Awaited Task2 执行"); return 2; });
    26     var res3 = await Task.Run(() => { Thread.Sleep(1000); log("Awaited Task3 执行"); return 3; });
    27 
    28     //不使用await:线程池多线程, 当前task不会等这个执行完,因为不是await,只是又开启了一个线程
    29     ThreadPool.QueueUserWorkItem(_ =>
    30     {
    31         Thread.Sleep(1000);
    32         log("ThreadPool.QueueUserWorkItem: 线程池多线程执行");
    33     });
    34 
    35     //不使用await:Task多线程, 当前task不会等这个执行完,因为不是await,只是又开启了一个任务
    36     Task.Run(() =>
    37     {
    38         Thread.Sleep(1000);
    39         log("Task.Run: Task多线程执行");
    40 
    41     });
    42    
    43     return res1 + res2 + res3;
    44 }
    45 //输出方法:显示当前线程号和输出信息
    46 static void log(string msg)
    47 {
    48     Console.WriteLine("线程{0}: {1}", Thread.CurrentThread.ManagedThreadId, msg);
    49 }
    复制代码

    执行结果如下:

    4. Async、Await

    这个是.NET 4.5的特性,所以要求最低.NET版本为4.5。

    看很多朋友还是使用的Thread来使用异步多线程操作,基本上看不见有使用Async、Await进行异步编程的。各有所爱吧,其实都可以。只要正确使用就行,不过还是写了这篇文章推荐大家使用Async、Await。 原因就是:可以跟写同步方法一样去异步编程。代码则就非常的清晰,就跟写普通的代码一样,不用关系如何去异步编程,也让很多初级程序员也能够异步编程了。下面是一个使用Thread 多线程实现的异步例子,以及一个使用Async与Await的异步例子,接下来我们再简单理解下Async与Await的相关技术说明。

    Thread多线程异步编程例子

    复制代码
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程测试开始..");
            Thread th = new Thread(ThMethod);
            th.Start();
            Thread.Sleep(1000);
            Console.WriteLine("主线程测试结束..");
            Console.ReadLine();
        }
     
     
        static void ThMethod()
        {
            Console.WriteLine("异步执行开始");
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("异步执行" + i.ToString() + "..");
                Thread.Sleep(1000);
            }
            Console.WriteLine("异步执行完成");
        }
    }
    复制代码

      

    以上代码运行效果如下图

    使用Async与Await进行异步编程

    复制代码
     1 static void Main(string[] args)
     2 {
     3     Console.WriteLine("主线程测试开始..");
     4     AsyncMethod();
     5     Thread.Sleep(1000);
     6     Console.WriteLine("主线程测试结束..");
     7     Console.ReadLine();
     8 }
     9 
    10 static async void AsyncMethod()
    11 {
    12     Console.WriteLine("开始异步代码");
    13     var result = await MyMethod();
    14     Console.WriteLine("异步代码执行完毕" + result.ToString());
    15 }
    16 
    17 static async Task<int> MyMethod()
    18 {
    19     for (int i = 0; i < 5; i++)
    20     {
    21         Console.WriteLine("异步执行" + i.ToString() + "..");
    22         await Task.Delay(1000); //模拟耗时操作
    23     }
    24     return 100;
    25 }
    复制代码

    运行效果:

    显而易见我们就跟写同步方法一样,完成了异步方法的编写,代码更清晰了。

    只有拥有async才能在其内部使用await关键字。异步方法可以具有Task、Task<>或void的返回类型;

    await关键字则是用于返回值是“可等待”类型(awaitable)的方法

    天空曾经飘过一片云,不留下一丝痕迹
  • 相关阅读:
    Kafka速览
    分布式消息中间件(二)ActiveMQ
    PageUtil 分页
    Tomcat配置
    CryptographyUtil盐加密
    InitComponent的使用
    Shiro权限总结
    【转】Java自学之路——by马士兵
    ExcelUtil
    Java操作Excel之Poi
  • 原文地址:https://www.cnblogs.com/wwwbdabc/p/11652592.html
Copyright © 2020-2023  润新知