• 第一节:复习委托,并且通过委托的异步调用开启一个新线程和异步回调、异步等待。


    一. 再谈委托

    1. 委托是一个关键字为delegate的自定义类型,通过委托可以把方法以参数的形式传递给另外一个方法,实现插件式的开发模式;

        同时调用委托的时候,委托所包含的所有方法都会被实现。

    2. 委托的发展历史:new实例化传递方法→直接等于方法名→delegate匿名方法→省略delegate→省略括号中的参数→当只有一个参数省略小括号

              →当方法体只有一行,省略大括号

     (详见:http://www.cnblogs.com/yaopengfei/p/6959141.html)

    3:常用的Action委托和Func委托

      A. Action<>委托,无返回值,至少有一个参数的委托

      B. Func<>委托,有返回值,可以无参数的委托(当然也可以有参数)

      C. Action委托,无参数无返回值的委托 

    二. 委托的调用

    委托的调用分为两种:

      A. 同步调用:Invoke方法,方法参数为函数的参数。

      B. 异步调用:BeginInvoke方法。

    其中无论是哪类调用,都有两类写法:

      ①:利用Action<>(或Func<>)内置委托,调用的时候赋值。

      ②:利用Action委托,直接赋值,然后调用。

     1         /// <summary>
     2         /// 执行动作:耗时而已
     3         /// </summary>
     4         private void TestThread2(string threadName1, string threadName2)
     5         {
     6             Console.WriteLine("线程开始:线程名为:{2}和{3},当前线程的id为:{0},当前时间为:{1},", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName1, threadName2);
     7             long sum = 0;
     8             for (int i = 1; i < 999999999; i++)
     9             {
    10                 sum += i;
    11             }
    12             Console.WriteLine("线程结束:线程名为:{2}和{3},当前线程的id为::{0},当前时间为:{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName1, threadName2);
    13         }

     

     

    三. 深入剖析BeginInvoke方法

       首先需要明确,该方法参数个数不定, 最后两个参数含义固定,如果不使用的话,需要赋值null;该方法最少两个参数,即方法无参数,这种情况下BeginInvoke中只有两个参数。此外,赋值的方法有几个参数,BeginInvoke中从左开始,新增几个参数。

      ①. 倒数第二个参数:是有一个参数值无返回值的委托,它代表的含义为,该线程执行完毕后的回调。

      ②. 倒数第一个参数:向倒数第二个参数(即回调)中传值,需要用AsyncState来接受。

      ③. 其它参数:即为赋值方法的参数。

    注:BeginInvoke的返回值等价于异步回调中的t。

     1   private void button13_Click(object sender, EventArgs e)
     2         {
     3             Stopwatch watch = new Stopwatch();
     4             watch.Start();
     5             Console.WriteLine("----------------- button1_Click 开始 主线程id为:{0}  --------------------------", Thread.CurrentThread.ManagedThreadId);
     6 
     7             Action<string> myFunc = this.TestThread;
     8             IAsyncResult asyncResult = null;
     9             //参数说明:前面几个参数都是方法的参数值,倒数第二个为异步调用的回调函数,倒数第一个为传给回调函数的参数
    10             for (int i = 0; i < 1; i++)
    11             {
    12                 string name = string.Format("button1_Click{0}", i);
    13                 asyncResult = myFunc.BeginInvoke(name, t =>
    14                    {
    15                        Console.WriteLine("我是线程{0}的回调", Thread.CurrentThread.ManagedThreadId);
    16                        //用 t.AsyncState 来获取回调传进来的参数
    17                        Console.WriteLine("传进来的参数为:{0}", t.AsyncState);
    18 
    19                        //测试一下异步返回值的结果
    20                        Console.WriteLine("异步返回值的结果:{0}", t.Equals(asyncResult));
    21                    }, "maru");
    22             }
    23 
    24             watch.Stop();
    25             Console.WriteLine("----------------- button1_Click 结束 主线程id为:{0}  总耗时:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
    26 
    27         }

    结果:

     

    四. 线程等待的三种方式

    1. asyncResult.IsCompleted属性,该方式会存在时间上的误差。

    2. WaitOne方法,可以控制一直等待or超时不再等待。

    3. EndInvoke方法,官方推荐的线程等待的方式。

    以上三种方式的局限性:批量线程等待的时候,不灵活,需要for循环了。

     1   private void button14_Click(object sender, EventArgs e)
     2         {
     3             Stopwatch watch = new Stopwatch();
     4             watch.Start();
     5             Console.WriteLine("----------------- button1_Click 开始 主线程id为:{0}  --------------------------", Thread.CurrentThread.ManagedThreadId);
     6 
     7             IAsyncResult asyncResult = null;
     8             Action<string> myFunc = this.TestThread;
     9             string name = string.Format("button1_Click{0}", 111);
    10             asyncResult = myFunc.BeginInvoke(name, t =>
    11              {
    12                  Console.WriteLine("我是线程{0}的回调", Thread.CurrentThread.ManagedThreadId);
    13                  //用 t.AsyncState 来获取回调传进来的参数
    14                  Console.WriteLine("传进来的参数为:{0}", t.AsyncState);
    15              }, "maru");
    16 
    17             //等待的方式1:会有时间上的误差
    18             //while (!asyncResult.IsCompleted)
    19             //{
    20             //    Console.WriteLine("正在等待中");
    21             //}
    22 
    23             // 等待的方式二:
    24             //asyncResult.AsyncWaitHandle.WaitOne();//一直等待
    25             //asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待
    26             //asyncResult.AsyncWaitHandle.WaitOne(1000);//等待1000毫秒,超时就不等待了
    27 
    28             //等待的方式三:
    29             myFunc.EndInvoke(asyncResult);
    30 
    31             watch.Stop();
    32             Console.WriteLine("----------------- button1_Click 结束 主线程id为:{0}  总耗时:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
    33 
    34         }

    下面是多个线程等待的情况:

     1   private void button15_Click(object sender, EventArgs e)
     2         {
     3             Stopwatch watch = new Stopwatch();
     4             watch.Start();
     5             Console.WriteLine("----------------- button1_Click 开始 主线程id为:{0}  --------------------------", Thread.CurrentThread.ManagedThreadId);
     6 
     7             List<IAsyncResult> list = new List<IAsyncResult>();
     8 
     9             for (int i = 0; i < 5; i++)
    10             {
    11                 string name = string.Format("button1_Click{0}", i);
    12                 Action myFunc = () =>
    13                 {
    14                     TestThread2(name, name);
    15                 };
    16                 var asyncResult = myFunc.BeginInvoke(null, null);
    17                 list.Add(asyncResult);
    18             }
    19 
    20             //下面是线程等待
    21             foreach (var item in list)
    22             {
    23                 item.AsyncWaitHandle.WaitOne(-1);
    24             }
    25 
    26             watch.Stop();
    27             Console.WriteLine("----------------- button1_Click 结束 主线程id为:{0}  总耗时:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
    28         }

    结果:

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    Java 介绍比较全面的一遍文章
    JSP页面中path和basepath的含义
    myeclipse2014 破解步骤
    word文档去掉复制过来的背景颜色
    String,创建对象问题
    使用Spring框架的好处(转帖)
    myeclipse中将整块的代码所选中的代码左右移动的快捷键
    点击关闭窗口时,弹出提醒的一个事件
    switch能使用的数据类型有6种
    观察者模式(设计模式_15)
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/8094512.html
Copyright © 2020-2023  润新知