《c# Invoke和BeginInvoke 区别.doc》由会员分享,可在线阅读,更多相关《c# Invoke和BeginInvoke 区别.doc(4页珍藏版)》请在金锄头文库上搜索。
1、c# Invoke和BeginInvoke 区别本文由mspecial_19贡献 doc文档可能在WAP端浏览体验不佳。建议您优先选择TXT,或下载源文件到本机查看。 c# Invoke 和 BeginInvoke 区别 2009-11-06 16:38 近日,被 Control 的 Invoke 和 BeginInvoke 搞的头大,就查了些相关的资料,整理如下. 感谢这篇文章对我的理解 Invoke 和 BeginInvoke 的真正含义 . (一)Control 的 Invoke 和 BeginInvoke 我们要基于以下认识: (1)Control 的 Invoke 和 BeginIn
2、voke 与 Delegate 的 Invoke 和 BeginInvoke 是不同的. (2)Control 的 Invoke 和 BeginInvoke 的参数为 delegate,委托的方法是在 Control 的线 程上执行的,也就是我们平时所说的 UI 线程. 我们以代码(一)来看(Control 的 Invoke) private delegate void InvokeDelegate(); private void InvokeMethod() /C 代码段 private void butInvoke_Click(object sender, EventArgs e) /A
3、代码段 this.Invoke(new InvokeDelegate(InvokeMethod); /B 代码段 你觉得代码的执行顺序是什么呢?记好 Control 的 Invoke 和 BeginInvoke 都执行在主线程 即 UI 线程上 ACB 解释:(1)A 在 UI 线程上执行完后,开始 Invoke,Invoke 是同步 (2)代码段 B 并不执行,而是立即在 UI 线程上执行 InvokeMethod 方法,即代码段 C. (3)InvokeMethod 方法执行完后,代码段 C 才在 UI 线程上继续执行. 看看代码(二),Control 的 BeginInvoke priv
4、ate delegate void BeginInvokeDelegate(); private void BeginInvokeMethod() /C 代码段 private void butBeginInvoke_Click(object sender, EventArgs e) /A 代码段 this.BeginInvoke(new BeginInvokeDelegate(BeginInvokeMethod); /B 代码段 你觉得代码的执行顺序是什么呢?记好 Control 的 Invoke 和 BeginInvoke 都执行在主线程 即 UI 线程上 ABC 慎重,这个只做参考 .,
5、我也不肯定执行顺序,如果有哪 位达人知道的话请告知. 解释: :(1)A 在 UI 线程上执行完后,开始 BeginInvoke,BeginInvoke 是异步 (2)InvokeMethod 方法,即代码段 C 不会执行,而是立即在 UI 线程上执行代码段 B. (3)代码段 B 执行完后(就是说 butBeginInvoke_Click 方法执行完后),InvokeMethod 方法, 即代码段 C 才在 UI 线程上继续执行. 由此,我们知道: Control 的 Invoke 和 BeginInvoke 的委托方法是在主线程,即 UI 线程上执行的.也就是 说如果你的委托方法用来取花费
6、时间长的数据, 然后更新界面什么的, 千万别在 UI 线程上调 用 Control.Invoke 和 Control.BeginInvoke,因为这些是依然阻塞 UI 线程的,造成界面的假死. 那么,这个异步到底是什么意思呢? 异步是指相对于调用 BeginInvoke 的线程异步,而不是相对于 UI 线程异步,你在 UI 线 程上调用 BeginInvoke ,当然不行了.摘自Invoke 和 BeginInvoke 的真正涵义一文 中的评论. BeginInvoke 的 原 理 是将调 用 的 方法 Marshal 成消 息 , 然 后调 用 Win32 API 中 的 RegisterW
7、indowMessage()向 UI 窗口发送消息. 摘自Invoke 和 BeginInvoke 的真正涵 义一文中的评论. (二)我们用 Thread 来调用 BeginInvoke 和 Invoke 我们开一个线程,让线程执行一些耗费时间的操作,然后再用 Control.Invoke 和 Control.BeginInvoke 回到用户 UI 线程,执行界面更新. 代码(三) Thread 调用 Control 的 Invoke private Thread invokeThread; private delegate void invokeDelegate(); private voi
8、d StartMethod() /C 代码段 Control.Invoke(new invokeDelegate(invokeMethod); /D 代码段 private void invokeMethod() /E 代码段 private void butInvoke_Click(object sender, EventArgs e) /A 代码段 invokeThread = new Thread(new ThreadStart(StartMethod); invokeThread.Start(); /B 代码段 你觉得代码的执行顺序是什么呢?记好 Control 的 Invoke 和
9、BeginInvoke 都执行在主线程 即 UI 线程上 A(Start 一开始 B 和 StartMethod 的 C 就同时执行)(C 执行完了,不管 B 有没有 执行完,invokeThread 把消息封送(invoke)给 UI 线程,然后自己等待)UI 线程处理完 butInvoke_Click 消息后,处理 invokeThread 封送过来的消息,执行 invokeMethod 方法,即代 码段 E,处理往后 UI 线程切换到 invokeThread 线程. 这个 Control.Invoke 是相对于 invokeThread 线程同步的,阻止了其运行. 解释: 1.UI 执
10、行 A 2.UI 开线程 InvokeThread,B 和 C 同时执行,B 执行在线程 UI 上,C 执行在线程 invokeThread 上. 3.invokeThread 封送消息给 UI,然后自己等待,UI 处理完消息后,处理 invokeThread 封送的消息,即代码段 E 4.UI 执行完 E 后,转到线程 invokeThread 上,invokeThread 线程执行代码段 D 代码(四) Thread 调用 Control 的 BeginInvoke private Thread beginInvokeThread; private delegate void beginI
11、nvokeDelegate(); private void StartMethod() /C 代码段 Control.BeginInvoke(new beginInvokeDelegate(beginInvokeMethod); /D 代码段 private void beginInvokeMethod() /E 代码段 private void butBeginInvoke_Click(object sender, EventArgs e) /A 代码段 beginInvokeThread = new Thread(new ThreadStart(StartMethod); beginInv
12、okeThread .Start(); /B 代码段 你觉得代码的执行顺序是什么呢?记好 Control 的 Invoke 和 BeginInvoke 都执行在主线程 即 UI 线程上 A 在 UI 线程上执行beginInvokeThread 线程开始执行,UI 继续执行代码段 B,并发 地 invokeThread 执 行 代 码 段 C 不 管 UI 有 没 有 执 行 完 代 码 段 B , 这 时 beginInvokeThread 线程把消息封送给 UI,单自己并不等待,继续向下执行UI 处理完 butBeginInvoke_Click 消息后,处理 beginInvokeThre
13、ad 线程封送过来的消息. 解释: 1.UI 执行 A 2.UI 开线程 beginInvokeThread,B 和 C 同时执行,B 执行在线程 UI 上,C 执行在线程 beginInvokeThread 上. 3.beginInvokeThread 封送消息给 UI,然后自己继续执行代码 D,UI 处理完消息后,处 理 invokeThread 封送的消息,即代码段 E 有点疑问:如果 UI 先执行完毕,是不是有可能过了段时间 beginInvokeThread 才把消息 封送给 UI,然后 UI 才继续执行封送的消息 E.如图浅绿的部分. Control 的 BeginInvoke 是相对于调用它的线程,即 beginInvokeThread 相对是异步的. 因此,我们可以想到.如果要异步取耗费长时间的数据,比如从数据库中读大量数据, 我们应该这么做. (1)如果你想阻止调用线程,那么调用代码(三),代码段 D 删掉,C 改为耗费长时间的操 作,因为这个操作是在另外一个线程中做的.代码段 E 改为更新界面的方法. (2)如果你不想阻止调用线程,那么调用代码(四),代码段 D 删掉,C 改为耗费长时间的 操作,因为这个操作是在另外一个线程中做的.代码段 E 改为更新界面的方法.