告别单线程,看看多线程能做什么
作为开发者,我觉我们的职责得就是把复杂的东西以一种简单的方式展示给用户或是普通使用者。
任何用户都不喜欢反应慢的程序。在计算机性能大幅度提高的今天,用户体验也就显得格外重要,没有人会有耐心去容忍你那糟糕的程序
接着上篇所讲,当程序中出现耗时较长的操作时,单线程往往就会力不从心,由于它是连续执行的,所以它没有办法跳过耗时较长的操作。
此时,使用多线程无疑是明智的选择,也是简单有效的解决方法。你可以将那些耗时的操作从UI线程中拿掉,放到另外一个非UI线程中,使得程序界面不用停下了等待耗时操作的完成,从而提高程序UI的执行速度。
下面我们就上篇文章中的代码稍作修改,,如下:
{
public SingleThread()
{
InitializeComponent();
}
private int ab = 0;
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(add_AB));
t.Start();
}
private int cd = 0;
private void button2_Click(object sender, EventArgs e)
{
add_CD();
tb_CD.Text = cd.ToString();
}
/// <summary>
/// 运算A+B
/// </summary>
private void add_AB()
{
Thread.Sleep(10000);//运算时间:10秒
ab= int.Parse(tb_A.Text) + int.Parse(tb_B.Text);
tb_AB.BeginInvoke(new add(addA_B), ab);
}
private delegate void add(int a);
private void addA_B(int result)
{
tb_AB.Text = result.ToString();
}
/// <summary>
/// 运算C+D
/// </summary>
private void add_CD()
{
cd = int.Parse(tb_C.Text) + int.Parse(tb_D.Text);
}
}
修改后的程序运行起来,用户体验就会好了很多,尽管A+B会消耗很长时间,但丝毫不会影响到C+D的操作。
在此,需要格外说明的是,Windows 窗体体系结构对线程有个格外严格的规定:除了极少数的例外情况,否则都不要在它的创建线程以外的线程中使用控件的任何成员。也就是说,我们界面中的所有控件有都是创建在UI线程中的,除UI线程外的其他线程都不能随意使用或修改控件中的任何属性,包括t_AB的值。而我们的“复杂计算”A+B的结果是需要显示到t_AB中的,所以不可避免地要修改它的值。
不过,在Winform的Control类中,有两个方法Invoke和BeginInvoke始终允许任何一个线程对Control进行invoke调用,进而修改控件的属性(接触WinForm的应该都知道,几乎任何控件都是继承自Control类,textbox也不例外)。所以与单线程相比,这里我们多定义了一个
private delegate void add(int a);
并且把t_AB的赋值语句改成了tb_AB.BeginInvoke(new add(addA_B), ab);
此外,在利用多线程编程的过程中,细心的人有时候可能会遇到这样一个情况:就是运行的项目命名已经关闭了,为什么打开资源管理器的时候在进程列表中还能看到程序在运行着呢?
我想这可能是你在程序中使用了异步委托调用,该调用以异步委托的方式运行在系统的线程池中,当你关闭程序时如果这个异步调用还没有结束,那么就会出现上述的情况。