您的位置:首页 > 其它

关于Control.Invoke与Control.BeginInvoke

2011-11-04 14:49 288 查看
[转自]http://www.cnblogs.com/conger/archive/2011/05/24/2055113.html

 最近在学多线程方面的知识,看了很多东西跟很多例子,有点感悟,写下来吧:

声明:本文中的一些字句跟例子是引用横竖都溢

http://www.cnblogs.com/smartls/archive/2011/04/08/2008981.html#2104297这里的;

现将关于利用Control.Invoke与Control.BeginInvoke对比解决窗体假死问题进行详细解说:

首先看的时候你需要有以下知识:

  如果你的后台线程在更新一个UI控件的状态后不需要等待,而是要继续往下处理,那么你就应该使用BeginInvoke来进行异步处理。如果你的后台线程需要操作UI控件,并且需要等到该操作执行完毕才能继续执行,那么你就应该使用Invoke。否则,在后台线程和主截面线程共享某些状态数据的情况下,如果不同步调用,而是各自继续执行的话,可能会造成执行序列上的问题,虽然不发生死锁,但是会出现不可预料的显示结果或者数据处理错误。

1、Control.Invoke,Control.BeginInvoke和delegate.Invoke,delegate.BeginInvoke是不同的。

2、Control.Invoke中的委托方法,执行在主线程,也就是我们的UI线程。而Control.BeginInvoke从命名上来看虽然具有异步调用的特征(Begin),但也仍然执行在UI线程。

3、如果在UI线程中直接调用Invoke和BeginInvoke,数据量偏大时,依然会造成UI的假死。

例子:



开始code:

private readonly int Max_Item_Count = 10000;

private void button1_Click(object sender,
EventArgs e)

{

new Thread((ThreadStart)(delegate()

{

for (int i = 0;
i < Max_Item_Count; i++)

{

// 此处警惕值类型装箱造成的"性能陷阱"

listView1.Invoke((MethodInvoker)delegate()

{

listView1.Items.Add(new ListViewItem(new string[]

{ i.ToString(), string.Format("This is No.{0} item",
i.ToString()) }));

});

};

}))

.Start();

}

  代码运行后,你将会看到一个飞速滚动的ListView列表,在加载的过程中,列表以令人眼花缭乱的速度添加数据,此时你尝试拉动滚动条,或者移动窗体,都会发现这次的效果与以往的”白板”、”假死”截然不同!这是一个令人欣喜的变化。
运行过程:



  从我的截图中可以看出,窗体在加载数据的过程中,依然绘制界面,并没有出现”假死”。
  如果上述代码调用的是Control.BeginInvoke,不仅会出现假死而且程序会发生些奇怪的现象,具体实现方法大家自己写写看吧,跟invoke差不多的。
现在就将Control.Invoke跟Control.BeginInvoke解释如下:
invoke是等到操作ui控件完毕后才执行的,所以它就等,然后再执行工作线程,执行工作线程这短暂的时间里主线程是空的

于是你可以在它界面上比划(点击,拉滚动条...)都没事,因为这时的工作主线程刚好可以做它,因为他是空的

至于begininvoke是由于它不等待操作ui完毕而是立即返回执行了工作线程,这样造成主线程跟工作线程同时在执行

没有主线程来理会你的比划(点击,拉滚动条...),所以你比划多了自然就卡死了。甚至

当工作线程跟主线程共享某些状态数据的情况下,工作线程的执行时间比主线程快时,将会造成执行序列上的问题,虽然不发生死锁,

但是会出现不可预料的显示结果或者数据处理错误。

 如果在主线程中加载大数据(很慢),那么即使用了invoke你比划也会卡住的。

另外还可以用线程池来解决;
MethodInvoker invoker = new MethodInvoker(Sleep);

invoker.BeginInvoke(null, null);


private void Sleep()

{

for (int i = 0; i < count; i++)

{

listView1.Invoke((MethodInvoker)delegate()

{

listView1.Items.Add(new ListViewItem(new string[] { i.ToString(), string.Format("This is No.{0} item", i.ToString()) }));

});

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐