.Net进阶系列(11)-异步多线程(委托BeginInvoke)(被替换)
一. BeginInvoke最后两个参数的含义
倒数第二个参数:指该线程执行完毕后的回调函数;倒数第一个参数:可以向回调函数中传递参数。
下面以一段代码说明:
/// <summary>
/// 执行动作:耗时而已
/// </summary>
private void TestThread(string threadName)
{
Console.WriteLine("线程开始:线程名为:{2},当前线程的id为:{0},当前时间为:{1},", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName);
long sum = ;
for (int i = ; i < ; i++)
{
sum += i;
}
Console.WriteLine("线程结束:线程名为:{2},当前线程的id为::{0},当前时间为:{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName);
}
private void button1_Click_1(object sender, EventArgs e)
{
Stopwatch watch = new Stopwatch();
watch.Start();
Console.WriteLine("----------------- 二.委托的异步调用测试 --------------------------");
Console.WriteLine("----------------- button1_Click 开始 主线程id为:{0} --------------------------", Thread.CurrentThread.ManagedThreadId); #region 2. 异步回调和异步参数
{
Action<string> myFunc = this.TestThread;
//参数说明:前面几个参数都是方法的参数值,倒数第二个为异步调用的回调函数,倒数第一个为传给回调函数的参数
for (int i = ; i < ; i++)
{
string name = string.Format("button1_Click{0}", i);
myFunc.BeginInvoke(name, t =>
{
Console.WriteLine("我是线程{0}的回调", Thread.CurrentThread.ManagedThreadId);
//用 t.AsyncState 来获取回调传进来的参数
Console.WriteLine("传进来的参数为:{0}", t.AsyncState);
}, "maru");
}
}
#endregion watch.Stop();
Console.WriteLine("----------------- button1_Click 结束 主线程id为:{0} 总耗时:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
}
结果:
二. 异步调用的三种书写
在上述代码中,我们发现BeginInvoke中,除了我们介绍的最后两个参数外,还有一个参数,传递进去了name,细心的人会发现,正式函数TestThread所需的参数,那么向函数中传递参数到底是在赋值委托时传递,还是委托调用时传递呢?
答案是两者皆可,如果在函数赋值委托时候传递,那么委托调用的时候,BeginInvoke只有最后两个参数。如果在委托调用的时候传递,BeginInvoke除了最后两个参数外,函数本身有几个参数,BeginInvoke前面将多出几个参数位置。
/// <summary>
/// 两个参数
/// </summary>
public static void TestThread(string txt1, string txt2)
{
Console.WriteLine("线程开始:测试参数为:{0}和{1},当前线程的id为:{2}", txt1, txt2, System.Threading.Thread.CurrentThread.ManagedThreadId);
long sum = ;
for (int i = ; i < ; i++)
{
sum += i;
}
Console.WriteLine("线程结束:测试参数为:{0}和{1},当前线程的id为:{2}", txt1, txt2, System.Threading.Thread.CurrentThread.ManagedThreadId);
}
//1. 方式一(使用多重载Action<>委托,函数的参数在BeginInvoke中传入)
{
Action<string, string> act = TestThread;
IAsyncResult iTest = act.BeginInvoke("参数1", "参数2", t =>
{
Console.WriteLine("我是线程执行后的回调");
Console.WriteLine(t.AsyncState); }, "我是传递参数的位置");
} //2. 方式二(使用Action委托,将参数值直接写在方法中,则无须向BeginInvoke中传入)
{
Action act2 = () => TestThread("参数1", "参数2");
act2.BeginInvoke(t =>
{
Console.WriteLine("我是线程执行后的回调");
Console.WriteLine(t.AsyncState); }, "我是传递参数的位置");
} //3. 方式三(下面两个等价,只不过是第一个省略{},在函数体中将方法写入)
{
Action<string, string> act3 = (a, b) => TestThread(a, b);
//Action<string, string> act3 = (a, b) =>
//{
// TestThread(a, b);
//};
IAsyncResult iTest = act3.BeginInvoke("参数1", "参数2", null, null);
}
三. 线程等待的三种方式
关于利用委托开启多线程,其线程等待有三种方式:endInvoke、waitone、IsCompleted,推荐使用endInvoke这种方式。
private void button1_Click_1(object sender, EventArgs e)
{
Stopwatch watch = new Stopwatch();
watch.Start();
Console.WriteLine("----------------- 二.委托的异步调用测试 --------------------------");
Console.WriteLine("----------------- button1_Click 开始 主线程id为:{0} --------------------------", Thread.CurrentThread.ManagedThreadId); #region 4. 异步等待
{
IAsyncResult asyncResult = null;
Action<string> myFunc = this.TestThread;
string name = string.Format("button1_Click{0}", );
asyncResult = myFunc.BeginInvoke(name, t =>
{
Console.WriteLine("我是线程{0}的回调", Thread.CurrentThread.ManagedThreadId);
//用 t.AsyncState 来获取回调传进来的参数
Console.WriteLine("传进来的参数为:{0}", t.AsyncState);
}, "maru"); //等待的方式1:会有时间上的误差
//while (!asyncResult.IsCompleted)
//{
// Console.WriteLine("正在等待中");
//} // 等待的方式二:
//asyncResult.AsyncWaitHandle.WaitOne();//一直等待
//asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待
//asyncResult.AsyncWaitHandle.WaitOne(1000);//等待1000毫秒,超时就不等待了 //等待的方式三:
myFunc.EndInvoke(asyncResult); }
#endregion watch.Stop();
Console.WriteLine("----------------- button1_Click 结束 主线程id为:{0} 总耗时:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
}
#endregion
运行上述代码,我们会发现,主界面又被卡在了,这正好印证了主线程在等待,结果如下:
四. 多个线程的等待
上面介绍的是单个线程的等待,有三种方式,那么如果同时开启了多个线程,主线程需要等待这多个线程,这时需要自己写循环,来进行线程等待。
{
List<IAsyncResult> list = new List<IAsyncResult>();
for (int i = ; i < ; i++)
{
string name1 = string.Format("ypf1-{0}", i);
string name2 = string.Format("ypf2-{0}", i);
Action act = () => TestThread(name1, name2);
IAsyncResult ir = act.BeginInvoke(null, null);
list.Add(ir);
}
//利用委托进行的异步多线程,采用上述方式二的等待最合理的
//缺点:整体上需要写循环,麻烦
foreach (var item in list)
{
item.AsyncWaitHandle.WaitOne();
}
}
.Net进阶系列(11)-异步多线程(委托BeginInvoke)(被替换)的更多相关文章
- .Net进阶系列(10)-异步多线程综述(被替换)
一. 综述 经过两个多个周的整理,异步多线程章节终于整理完成,如下图所示,主要从基本概念.委托的异步调用.Thread多线程.ThreadPool多线程.Task.Parallel并行计算.async ...
- .Net进阶系列(15)-异步多线程(线程的特殊处理和深究委托赋值)(被替换)
1. 线程的异常处理 我们经常会遇到一个场景,开启了多个线程,其中一个线程报错,导致整个程序崩溃.这并不是我们想要的,我需要的结果是,其中一个线程报错,默默的记录下,其它线程正常进行,保证程序整体可以 ...
- .Net进阶系列(13)-异步多线程(Task和Parallel)(被替换)
一. Task开启多线程的三种形式 1. 利用TaskFactory下的StartNew方法,向StartNew传递无参数的委托,或者是Action<object>委托. 2. 利用Tas ...
- .Net进阶系列(12)-异步多线程(Thread和ThreadPool)(被替换)
一. Thread多线程 1. 两种使用方式 通过F12查看Thread后,发现有两类构造函数,ParameterizedThreadStart和ThreadStart,其中 ThreadStar ...
- .Net进阶系列(14)-异步多线程(async和await)(被替换)
1. 方法名前只有async,但是方法中Task实例前没有await关键字,该方法和普通方法没有什么区别,但是会报一个警告. #region 情况一 /// <summary> /// ...
- SilkTest高级进阶系列9 – 异步执行命令
我们常常会使用sys_execute函数执行一些外部的程序或者命令来做一些事情,但是由于sys_execute是一个同步的函数,它会等待执行的命令完成后才会返回.在大多数情况下,这个函数足够用了. 但 ...
- .NET进阶篇-语言章-2-Delegate委托、Event事件
知识只有经过整理才能形成技能 整个章节分布简介请查看第一篇 内容目录 一.概述 二.解析委托知识点 1.委托本质 2.委托的使用 3.委托意义 逻辑解耦,减少重复代码 代码封装支持扩展 匿名方法和La ...
- 异步和多线程,委托异步调用,Thread,ThreadPool,Task,Parallel,CancellationTokenSource
1 进程-线程-多线程,同步和异步2 异步使用和回调3 异步参数4 异步等待5 异步返回值 5 多线程的特点:不卡主线程.速度快.无序性7 thread:线程等待,回调,前台线程/后台线程, 8 th ...
- .NET进阶篇06-async异步、thread多线程1
知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 异步多线程挺大一块内容,既想拆开慢慢学,又想一股脑全倒出.纠结再三,还是拆开吃透,也不至于篇幅过长,劝退许多人 本篇先做一个概述,列明一些基本概 ...
随机推荐
- Node post请求 通常配合ajax
//处理客户post请求//*1:加载相应模块 http express querystring//*2:创建web服务器//*3:监听端口8080const http = require(" ...
- 金蝶特性配置(超级BOM)
特性配置 特性物料 物料和特性的对应关系 自动新增物料的系统设置 特性物料自动新增 自动新增的特性配置方案 相关表 ICPlan_CharacteristicEntry
- Linux基础学习(9)--文件系统管理
第九章——文件系统管理 一.回顾分区和文件系统 1.分区类型: 2.分区表示方法: 3.文件系统: 二.文件系统常用命令 1.df命令.du命令.fsck命令和dump2fs命令: (1)文件系统查看 ...
- schema举例一
schema举例一: <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs=& ...
- 通俗理解TCP/IP协议三次握手四次分手流程
转自:https://blog.csdn.net/special23/article/details/54137298 三次握手流程 客户端发个请求“开门呐,我要进来”给服务器 服务器发个“进来吧,我 ...
- IDEA上传码云报错Push rejected: Push to origin/master was rejected
原因是README.md文件冲突,码云上在创建项目的时候不要初始化README.md,然后再用IDEA上传
- 【HDU 5363】Key Set(和为偶数的子集个数)
题 Description soda has a set $S$ with $n$ integers $\{1, 2, \dots, n\}$. A set is called key set if ...
- CodeForces 464E The Classic Problem | 呆克斯歘 主席树维护高精度
题意描述 有一个\(n\)点\(m\)边的无向图,第\(i\)条边的边权是\(2^{a_i}\).求点\(s\)到点\(t\)的最短路长度(对\(10^9 + 7\)取模). 题解 思路很简单--用主 ...
- THUWC2019 摸鱼记
Day1 菜狗选手无人权,衣服没有海星,狗牌手写全糊,餐票不发刷卡,住宿自理宾馆. 人菜没办法. 感受到了自己智商低 不想写了 想原地退役 不知道还要不要走下去
- android 之 Hnadler 、Message 、Looper
Handler定义: 主要接受子线程发送来的数据,并用此数据配合主线程更新UI. 为什么要用Handler? 我们手机当中的很多功能或操作是不能都放在Activity当中的,比如下载文件.处理大量数据 ...