zoukankan      html  css  js  c++  java
  • Task多线程的常规用法

    Task被认为优于线程池

    利用拉姆达表达式和本身的泛型支持,可以轻松实现指向常用的方法。

    注意:委托(含拉姆达表达式)中调用的方法,其参数如果是变量,它的值取决于运行的那一刻内存里的值。如果希望在创建任务的时候值是固定的,必须用object参数state作为创建任务的状态,把值给进去。

    以下两种用法,结果是不同的。

    static void Main(string[] args)
            {
                Task t;
                for (int i = 0; i < 10; i++)
                {
                    //t = new Task(print1,i+1);
                    t = new Task(() => print1(i + 1));
                    t.Start();
                }
                Console.ReadKey();
            }
            static void print1(object x)
            {
                Console.Write($"{x}	");
            }

    Task常规用法为:

    1、有参action或func:(//下面两行中的1500和2500都是object类型,t1指向Func,t2指向Action

    var t1 = new Task<int>(add2, 1500);
    var t2 = new Task(add1, 2500);
                t1.Start();
                t2.Start();

    2、对无参action或func,除了上面的用法,也可以简写为:

    var t1 = Task.Run(say);
                var t2 = Task.Run<int>(say1);

    3、某线程结束后可以直接回调

    var t = new Task(DoSth);
                t.Start();
                t.ContinueWith(showit, "hi");

    如上,后两句可以调换位置。

    4、取结果用Task对象的Result属性。会堵塞主线程。

    static void Main(string[] args)
            {
                DateTime d1 = DateTime.Now;
                var t1 = Task.Run(say);
                var t2 = Task.Run<int>(say1);
                Console.WriteLine(t2.Result);
                Task.WhenAll(t1,t2).ContinueWith(showtime, d1);
                Console.WriteLine("hi in main");
                Console.ReadKey();
            }
            static void say()
            {
                Console.WriteLine("hi in say");
            }
            static int say1()
            {
                Thread.Sleep(1000);
                return 1;
            }
    static void showtime(Task t,Object o)
            {
                DateTime dt2 = (DateTime)o,dt3=DateTime.Now;
                var span= dt3- dt2;
                Console.WriteLine(span.TotalMilliseconds);
            }

    运行结果:

     另综合例1:

    static void Main(string[] args)
            {
                //Task t3 = new Task(() => add1(-25,-29));
                //t3.Start();
                Task t3 = Task.Run(() => add1(-25, -29));//上两行的立即模式
    
                //Task<int> t4 = new Task<int>(() => add2(66,77));
                //t4.Start();
                Task<int> t4 = Task.Factory.StartNew(() => add2(66, 77));//上两行的立即模式,不用start
                //Task<int> t4 = Task.Run<int>(() => add2(66, 77));//同上一行
    
                t3.Wait(1000);//程序等待t3一秒(暂停)
                //Task[] ta = new Task[] { t3, t4 };
                //Task.WaitAll(ta);//同步等待(暂停)无返回
                //Task.WhenAll(ta).ContinueWith((t) => Console.WriteLine("lalala"));//异步等待(后续)when会新建一个任务
    
                //Task.WhenAll<int>()....
                //用法理解:异步,所有任务返回结果,结果组成结果集,被整个方法返回的任务以"result[]"属性的方式呈现。见后面的综合例2
    
                //以下两种,用法与all类似
                //Task.WaitAny();//返回整数,表示最先完成的task在数组中的下标。超时为-1
                //Task.WhenAny();//返回最先完成的任务
    
                if(t3.IsCompleted)
                {
                    Console.WriteLine("ok");
                }
                else
                {
                    Console.WriteLine("no");
                }
                Console.WriteLine(t4.Result);
                Console.ReadKey();
            }
            static void add1(int x, int y)
            {
                Thread.Sleep(2000);
                Console.WriteLine( x + y);
            }
            static int add2(int x,int y)
            {
                return x+y;
            }

    另综合例2,多任务计算1+2+3+...+100:

     1 class Program
     2     {
     3         //无论有参无参,action都比func简单。
     4         //这里故意把问题复杂化,以做练习~_~
     5         //其实使用action,全局变量累加更容易懂。
     6         //计算1+2+...+100
     7         static void Main(string[] args)
     8         {
     9             List<Task<int>> tasks = new List<Task<int>>();
    10             Task<int> t;
    11             for (int i = 1; i < 100; i += 10)
    12             {
    13                 t = new Task<int>(add10, new MyData(i));
    14                 tasks.Add(t);
    15                 t.Start();
    16             }
    17             Task.WhenAll(tasks.ToArray()).ContinueWith(printsum);
    18             Console.WriteLine($"主线程结束");
    19             Console.ReadKey();
    20         }
    21         //计算10个数的和
    22         static int add10(object x)
    23         {
    24             int y = ((MyData)x).v,s=0;
    25             for (int i = 0; i <= 9; i++)
    26             {
    27                 s += y+i;
    28             }
    29             return s;
    30         }
    31         //Task<int[]>是main当中Task.WhenAll(tasks.ToArray())的返回类型
    32         //含义:每个任务都返回一个整数,所有任务完成后,就返回一个新任务,它有一个整数数组作为每个任务的结果。
    33         //这里也就自然是ContinueWith的参数。(兰姆达表达式的习惯)
    34         //打印所有任务的结果之和(即新任务的结果属性数组里的所有元素之和)
    35         static void printsum(Task<int[]> ts)
    36         {
    37             int s = 0;
    38             foreach (var item in ts.Result)
    39             {
    40                 s += item;
    41             }
    42             Console.WriteLine($"Sum is {s}");
    43         }
    44     }
    45     class MyData
    46     {
    47         public int v;
    48         public MyData(int v1)
    49         {
    50             v = v1;
    51         }
    52     }

    结果:

     关于任务的取消,微软提供了takon(票据、凭据)的方式。

    个人觉得1、正常运行的时候,不太有这个需求;2、可以主任务和分任务都能访问到的变量(比如全局变量)来取代它,少一点学习成本。

    此处略。

  • 相关阅读:
    windows XP 下的DTRACE 跟踪 学习
    copy to tmp table
    快麦
    SQL SERVER BOOK
    启锐电子面单驱动
    grep---find
    mysql中kill掉所有锁表的进程
    sqlserverinternals.com
    从顺序随机I/O原理来讨论MYSQL MRR NLJ BNL BKA
    解析MYSQL BINLOG二进制格式
  • 原文地址:https://www.cnblogs.com/wanjinliu/p/12673917.html
Copyright © 2011-2022 走看看