一. 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)(被替换)的更多相关文章

  1. .Net进阶系列(10)-异步多线程综述(被替换)

    一. 综述 经过两个多个周的整理,异步多线程章节终于整理完成,如下图所示,主要从基本概念.委托的异步调用.Thread多线程.ThreadPool多线程.Task.Parallel并行计算.async ...

  2. .Net进阶系列(15)-异步多线程(线程的特殊处理和深究委托赋值)(被替换)

    1. 线程的异常处理 我们经常会遇到一个场景,开启了多个线程,其中一个线程报错,导致整个程序崩溃.这并不是我们想要的,我需要的结果是,其中一个线程报错,默默的记录下,其它线程正常进行,保证程序整体可以 ...

  3. .Net进阶系列(13)-异步多线程(Task和Parallel)(被替换)

    一. Task开启多线程的三种形式 1. 利用TaskFactory下的StartNew方法,向StartNew传递无参数的委托,或者是Action<object>委托. 2. 利用Tas ...

  4. .Net进阶系列(12)-异步多线程(Thread和ThreadPool)(被替换)

    一. Thread多线程   1. 两种使用方式 通过F12查看Thread后,发现有两类构造函数,ParameterizedThreadStart和ThreadStart,其中 ThreadStar ...

  5. .Net进阶系列(14)-异步多线程(async和await)(被替换)

    1.  方法名前只有async,但是方法中Task实例前没有await关键字,该方法和普通方法没有什么区别,但是会报一个警告. #region 情况一 /// <summary> /// ...

  6. SilkTest高级进阶系列9 – 异步执行命令

    我们常常会使用sys_execute函数执行一些外部的程序或者命令来做一些事情,但是由于sys_execute是一个同步的函数,它会等待执行的命令完成后才会返回.在大多数情况下,这个函数足够用了. 但 ...

  7. .NET进阶篇-语言章-2-Delegate委托、Event事件

    知识只有经过整理才能形成技能 整个章节分布简介请查看第一篇 内容目录 一.概述 二.解析委托知识点 1.委托本质 2.委托的使用 3.委托意义 逻辑解耦,减少重复代码 代码封装支持扩展 匿名方法和La ...

  8. 异步和多线程,委托异步调用,Thread,ThreadPool,Task,Parallel,CancellationTokenSource

    1 进程-线程-多线程,同步和异步2 异步使用和回调3 异步参数4 异步等待5 异步返回值 5 多线程的特点:不卡主线程.速度快.无序性7 thread:线程等待,回调,前台线程/后台线程, 8 th ...

  9. .NET进阶篇06-async异步、thread多线程1

    知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 异步多线程挺大一块内容,既想拆开慢慢学,又想一股脑全倒出.纠结再三,还是拆开吃透,也不至于篇幅过长,劝退许多人 本篇先做一个概述,列明一些基本概 ...

随机推荐

  1. VC6到VC2010,项目迁移错误

    错误信息: error C2440: “static_cast”: cannot from “BOOL (__thiscall CSelectRect::* )(void)” to “BOOL (__ ...

  2. Jmeter 通过json Extracted 来获取 指定的值的id

    在没有 精确或模糊查询的接口时可以使用jmeter 获取指定的值的ID import java.lang.String ; String getTargetName="iphone632g& ...

  3. Windows平台下面Oracle11.2.0.1 升级Oracle11.2.0.4 的简单步骤

    1. 首先查看数据库的版本: 2. ESXi 上面的虚拟机挂在 oracle11.2.0.4的 iso磁盘 3. 执行set 进行升级 4. 安装选项进行选择 升级现有的数据库 5. 注意安装位置必须 ...

  4. [转帖新闻]Windows 7时代即将终结:曾有多辉煌 如今就有多凄凉

    Windows 7时代即将终结:曾有多辉煌 如今就有多凄凉 投递人 itwriter 发布于 2019-01-18 10:47 评论(4) 有834人阅读 [收藏] « » 文/屠敏 来源:CSDN( ...

  5. linux学习之centos(三):mysql数据库的安装和配置

    前言:mysql简介 说到数据库,我们大多想到的是关系型数据库,比如mysql.oracle.sqlserver等等,这些数据库软件在windows上安装都非常的方便,在Linux上如果要安装数据库, ...

  6. 软件工程_9th weeks

    PSP DATE START_TIME END_TIME EVENT TYPE       TIME 4.30-5.3 5:30 4:00 旅游 娱乐       72h 5.3 14:00 17:0 ...

  7. atan和unwrap解卷绕

    要计算一个系统相频特性,就要用到反正切函数,计算机中反正切函数规定,在一.二象限中的角度为0-pi,三四象限的角度为0--pi. 若一个角度从0变到2pi,但实际得到的结果是0-pi,再由-pi-0, ...

  8. 优步加入Linux基金会:支持开源

    导读 当地时间11月16日,优步在Uber Open Summit 2018年度峰会上宣布加入Linux基金会,并作为金级会员坚定支持对开源工具的使用和贡献. 优步CEO Thuan Pham将Lin ...

  9. 微软开放 6 万项 Linux 专利,有哪些是我们该注意的?

    导读 上周,微软宣布正式加入 Open Invention Network (“OIN”) 社区,开放其 6 万多项 Linux 专利.消息一出,许多人疑惑微软为什么要这么做?作为普通开发者,是否能使 ...

  10. Spark RDD操作之Map系算子

    在linux系统上安装solrCloud 1.依赖: JRE solr7.3 需要 java1.8 独立的zookeeper服务 ,zookeeper安装请参考: http://zookeeper.a ...