一. 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. 关于ArcGIS常用功能的实现

    关于ArcGIS中常见的一些功能的总结,一般首先在前台中放置地图,代码如下所示: <esri:Map Grid.Row="0" Grid.Column="0&quo ...

  2. shell 学习笔记一

    一.布尔运算符列表 a=10b=20 !非运算,表达式为 true 则返回 false,否则返回 true.[ ! false ] 返回 true. -o或运算,有一个表达式为 true 则返回 tr ...

  3. CnPack实用功能推荐

    已经使用CnPack好几年了,这个插件太好了,现在离开它我都不会写代码了,现在将使用心得与大家分享一下: 1.代码助手非常好用,只需要输入几个字符后,自动出现提示列表,真是懒人的福音呀. 2.代码高亮 ...

  4. 平衡树及笛卡尔树讲解(旋转treap,非旋转treap,splay,替罪羊树及可持久化)

    在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用 ...

  5. Codeforces Round #418 (Div. 2) B. An express train to reveries

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  6. MT【32】内外圆(Apollonius Circle)的几何证明

    另一方面,如果 M 满足(1)式,那么M必然在以PQ为直径的圆上.事实上当M为P或者Q时,这是显然的.当M异于P,Q时,由$\frac{|MB|}{|MC|}=\frac{|PB|}{|PC|}=\l ...

  7. 自学Python1.4-Centos内vim中文乱码问题

    自学Python之路 自学Python1.4-Centos内vim中文乱码问题 1. 登陆的系统---区域语言设置 1.1查看安装中文包: 查看系统是否安装中文语言包 (列出所有可用的公共语言环境的名 ...

  8. 【BZOJ1820】[JSOI2010]快递服务(动态规划)

    [BZOJ1820][JSOI2010]快递服务(动态规划) 题面 BZOJ 洛谷 题解 考虑无脑四维\(dp\).\(f[i][a][b][c]\),表示当前处理到第\(i\)个任务,三辆车的位置分 ...

  9. BZOJ 2434 阿狸的打字机 | AC自动机

    题目戳这里 AC自动机上有神奇的东西叫做fail指针--所有fail指针连起来恰好构成一棵以1为根的树! 而这道题问x在y中出现过多少次,就是问Trie树上根到y的结束节点的路径上有多少节点能通过跳f ...

  10. 洛谷 P1879 [USACO06NOV]玉米田 解题报告

    P1879 [USACO06NOV]玉米田Corn Fields 题目描述 农场主\(John\)新买了一块长方形的新牧场,这块牧场被划分成\(M\)行\(N\)列\((1 ≤ M ≤ 12; 1 ≤ ...