一. 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. Activiti流程编辑器针对自定义用户角色表优化改造

    本文目的: 针对自定义的用户.角色表,对Activiti的在线流程设计器进行优化改造,使之能直接在图形界面上完成对节点办理人.候选人.候选组的配置,不需要先去查数据库中的用户ID.角色ID等信息再填入 ...

  2. React 支持JS

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  3. 关于python项目路径导入自己写的库出错的一点思考

    其实也是在写自己项目的时候遇到的,以前也遇到了但是一直采取的是回避的策略,这次总算弄清楚所以总结一下. 这个项目的顶级目录是medivac,他本身是一个python模块. 熟悉flask的人都知道,在 ...

  4. poj3061(尺取法)

    ---恢复内容开始--- 题目意思:给你一段非负序列,再给你一个值k,找出这段序列中最少的连续子序列使得和为k: 解题思路:因为都是正数,我们只需要找到一段区间不大于k,就停止,然后左边趋近看是否能得 ...

  5. BZOJ1070[SCOI2007]修车——最小费用最大流

    题目描述 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待 ...

  6. 小程序源码下载[demo整理自github]

    微信小程序的火热程度大家都有所了解,也有很多牛人写了不错的小程序,今天ytkah就整理一些github上的小程序开源项目,源码可以直接下载来用,感兴趣的朋友赶紧去看看吧!以下小程序排名按star的数量 ...

  7. HDU-3746-KMP理解失配

    这个有点意思,要理解失配数组 题意是要计算出需要构造成循环节相连的最小个数 利用失配构造函数求出单个循环节,然后计算出需要的加上的珠子个数 #include <cstdio> #inclu ...

  8. [ctsc2018] 混合果汁 【可持久化线段树】【二分答案】

    题目分析 首先考虑到最小值最大,二分答案.假设答案为k,显然这满足单调性.如果某个k使得这个情况下选不出.那么比k大的一定也选不出,所以二分答案. 接着我们可以贪心,当我们确认了k以后,一定会优先选费 ...

  9. Android Service服务的生命周期

    与activity类似,服务也存在生命周期回调方法,你可以实现这些方法来监控服务的状态变化,并在适当的时机执行一些操作. 以下代码提纲展示了服务的每个生命周期回调方法: public class Ex ...

  10. NinePatch图片

    绍 参考 :http://blog.sina.com.cn/s/blog_5033827f0100r4dm.html NinePatch图片以*.9.png结尾,和普通图片的区别是四周多了一个边框(如 ...