关于Control.Invoke与Control.BeginInvoke

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

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

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()) }));      
                });
            }

        }

posted on 2011-05-24 10:35  congplayer  阅读(644)  评论(3编辑  收藏  举报

导航