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

一. 再谈委托

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         }

复制代码

结果:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438277.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第二节:深入剖析Thread的五大方法、数据槽、内存栅栏。

一. Thread及其五大方法 Thread是.Net最早的多线程处理方式&#xff0c;它出现在.Net1.0时代&#xff0c;虽然现在已逐渐被微软所抛弃&#xff0c;微软强烈推荐使用Task(后面章节介绍)&#xff0c;但从多线程完整性的角度上来说&#xff0c;我们有必要了解下N年前多线程的是怎么…

HashMap和ConcurrentHashMap

HashMap: 线程不安全&#xff0c;不支持并发操作&#xff0c;键-值&#xff08;key-value&#xff09;都允许为空、、不保证有序 在 JDK1.7 中&#xff0c;HashMap 采用头插法插入元素&#xff0c;因此并发情况下会导致环形链表&#xff0c;产生死循环。 虽然 JDK1.8 采用了…

第三节:ThreadPool的线程开启、线程等待、线程池的设置、定时功能

一. ThreadPool简介 ThreadPool简介&#xff1a;ThreadPool是一个线程池&#xff0c;当你需要开启n个线程时候&#xff0c;只需把这个指令抛给线程池&#xff0c;它将自动分配线程进行处理&#xff0c;它诞生于.Net 2.0时代。 ThreadPool与Thread的区别&#xff1a; ①&#xf…

第十节:进一步扩展两种安全校验方式

一. 简介 简介&#xff1a; 上一节中&#xff0c;主要介绍了JWT校验&#xff0c;它是无状态的&#xff0c;是基于Token校验的一种升级&#xff0c;它适用的范围很广泛&#xff0c;APP、JS前端、后台等等客户端调用服务器端的校验。本节补充几种后台接口的校验方式&#xff0c;它…

第十一节:WebApi的版本管理的几种方式

一. 背景和方案 1. 多版本管理的概念 Android 、IOS等 App 存在着多版本客户端共存的问题&#xff1a;App 最新版已经升级到了5.0 了&#xff0c;但是有的用户手机上还运行着 4.8、3.9 甚至2.2 版本的 App&#xff0c;由于早期没有内置升级机制、用户不会升级、用户拒绝升级等…

类加载器分类

类加载器干就是将对应类的.class文件中的二进制流加载到内存空间,只管加载&#xff0c;只要符合文件结构就加载&#xff0c;至于能否运行&#xff0c;它不负责 类加载器的分类 1.启动类加载器 2.扩展类加载器 3.应用程序类加载器 委托机制:双亲委派模型 当一个类加载的过…

第十二节:WebApi自动生成在线Api文档的两种方式

一. WebApi自带生成api文档 1. 说明 通过观察&#xff0c;发现WebApi项目中Area文件夹下有一个HelpPage文件夹&#xff0c;如下图&#xff0c;该文件夹就是WebApi自带的生成Api的方式&#xff0c;如果该文件夹没了&#xff0c;可以通过Nuget安装&#xff1a;Microsoft.AspNet.…

JVM 组成部分

JVM可以分为3大部分&#xff1a;类加载器&#xff0c;运行时数据区和执行引擎。 类加载器负责加载.class 文件 运行时数据区负责存放.class 文件&#xff0c;分配内存。运行时数据区又分为5个部分: 方法区&#xff1a;负责存放.class 文件&#xff0c;方法区里有一块区域是运…

第十三节:Asp.Net Core WebApi基础总结和请求方式-第十八节

一. 基础总结 1.Restful服务改造 Core下的WebApi默认也是Restful格式服务&#xff0c;即通过请求方式(Get,post,put,delete)来区分请求哪个方法&#xff0c;请求的URL中不需要写方法名。 但是我们不喜欢这种方式&#xff0c;所以我们将默认的路由规则 [Route("api/[contr…

第十四节:Asp.Net Core WebApi生成在线文档-第十九节

一. 基本概念 1.背景 使用 Web API 时&#xff0c;了解其各种方法对开发人员来说可能是一项挑战。 Swagger 也称为OpenAPI&#xff0c;解决了为 Web API 生成有用文档和帮助页的问题。 它具有诸如交互式文档、客户端 SDK生成和 API 可发现性等优点&#xff0c;目前有两种实现方…

第十五节:Asp.Net Core MVC和WebApi路由规则的总结和对比-第二十节

一. Core Mvc 1.传统路由 Core MVC中&#xff0c;默认会在 Startup类→Configure方法→UseMvc方法中&#xff0c;会有默认路由&#xff1a;routes.MapRoute("default", "{controllerHome}/{actionIndex}/{id?}"); 等价于 app.UseMvcWithDefaultRoute(); …

第四节:Task的启动的四种方式以及Task、TaskFactory的线程等待和线程延续的解决方案

一. 背景 揭秘&#xff1a; 在前面的章节介绍过&#xff0c;Task出现之前&#xff0c;微软的多线程处理方式有&#xff1a;Thread→ThreadPool→委托的异步调用&#xff0c;虽然也可以基本业务需要的多线程场景&#xff0c;但它们在多个线程的等待处理方面、资源占用方面、线程…

第五节:Task构造函数之TaskCreationOptions枚举处理父子线程之间的关系。

一. 整体说明 揭秘&#xff1a; 通过F12查看Task类的源码(详见下面的截图)&#xff0c;发现Task类的构造函数有有一个参数为&#xff1a;TaskCreationOptions类型&#xff0c;本章节可以算作是一个扩展章节&#xff0c;主要就来研究TaskCreationOptions类的作用。 该类主要用来…

第六节:深入研究Task实例方法ContinueWith的参数TaskContinuationOptions

一. 整体说明 揭秘&#xff1a; 该章节的性质和上一个章节类似&#xff0c;也是一个扩展的章节&#xff0c;主要来研究Task类下的实例方法ContinueWith中的参数TaskContinuationOptions。 通过F12查看TaskContinuationOptions的源码&#xff0c;知道主要有这么几个参数&#xf…

第七节:利用CancellationTokenSource实现任务取消和利用CancellationToken类检测取消异常。

一. 传统的线程取消 所谓的线程取消&#xff0c;就是线程正在执行的过程中取消线程任务。 传统的线程取消&#xff0c;是通过一个变量来控制&#xff0c;但是这种方式&#xff0c;在release模式下&#xff0c;被优化从cpu高速缓存中读取&#xff0c;而不是从内存中读取&#xf…

第八节:Task的各类TaskTResult返回值以及通用线程的异常处理方案。

一. Task的各种返回值-Task<TResult> PS&#xff1a; 在前面章节&#xff0c;我们介绍了Task类开启线程、线程等待、线程延续的方式&#xff0c;但我们并没有关注这些方式的返回值&#xff0c;其实他们都是有返回值的Task<TResult>&#xff0c;然后可以通过Task的…

第九节:深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)

一. 并行编程 1. 区分串行编程和串行编程 ①. 串行编程&#xff1a;所谓的串行编程就是单线程的作用下&#xff0c;按顺序执行。(典型代表for循环 下面例子从1-100按顺序执行) ②. 并行编程&#xff1a;充分利用多核cpu的优势&#xff0c;同时开启多个线程并行执行。(典型代表…

第十节:利用async和await简化异步编程模式的几种写法

一. async和await简介 PS&#xff1a;简介 1. async和await这两个关键字是为了简化异步编程模型而诞生的&#xff0c;使的异步编程更简洁&#xff0c;它本身并不创建新线程&#xff0c;但在该方法内部开启多线程&#xff0c;则另算。 2. 这两个关键字适用于处理一些文件IO操作。…

第十一节:深究用户模式锁的使用场景(异变结构、互锁、旋转锁)

一. 锁机制的背景介绍 本章节&#xff0c;将结合多线程来介绍锁机制&#xff0c; 那么问题来了&#xff0c;什么是锁呢&#xff1f; 为什么需要锁&#xff1f; 为什么要结合多线程来介绍锁呢&#xff1f;锁的使用场景又是什么呢&#xff1f; DotNet中又有哪些锁呢&#xff1f; …

第十三节:实际开发中使用最多的监视锁Monitor、lock语法糖的扩展、混合锁的使用(ManualResetEvent、SemaphoreSlim、ReaderWriterLockSlim)

一. 监视锁(Monitor和lock) 1. Monitor类&#xff0c;限定线程个数的一把锁&#xff08;Synchronized lock是他的语法糖&#xff09;&#xff0c;两个核心方法&#xff1a; Enter&#xff1a;锁住某个资源。 Exit&#xff1a;退出某一个资源。 测试案例&#xff1a;开启5个线…