关于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()) }));
});
}
}
最近在学多线程方面的知识,看了很多东西跟很多例子,有点感悟,写下来吧:
声明:本文中的一些字句跟例子是引用横竖都溢
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()) }));
});
}
}
相关文章推荐
- 关于Control.Invoke与Control.BeginInvoke
- 【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang)
- 不同线程间通信,使用Control的Invoke和BeginInvoke的方法
- Control中Invoke与BeginInvoke区别
- control 的invoke 和begininvoke
- WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用
- SQL Server 2008 : Invoke or BeginInvoke cannot be called on a control until the window handle has ..
- Control的Invoke和BeginInvoke 是相对于支线线程(因为一般在支线线程中调用,用来更新主线程ui)Invoke立即插入主线程中执行,而BeginInvoke 要等主线程结束才执行
- control的Invoke和BeginInvoke
- [转载]Winform中Control的Invoke与BeginInvoke方法
- 浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别
- C#-Control.Invoke与Control.BeginInvoke
- Thread.Start和Delegate.BeginInvoke 以及Control.BeginInvoke
- C# 对委托的BeginInvoke,EndInvoke 及Control 的BeginInvoke,EndInvoke 的理解
- 转一篇文章关于.Net的Invoke和BeginInvoke 写得挺好!
- 委托的Invoke 和 BeginInvoke 与Control的Invoke和BeginInvoke(转-因为写得很好)
- 转:C# 对委托的BeginInvoke,EndInvoke 及Control 的BeginInvoke,EndInvoke 的理解
- Control中的beginInvoke于Delegate中的beginInove一起使用
- WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用
- 千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死