多线程耗时操作及界面更新

来源:互联网 发布:网络道德的本质 编辑:程序博客网 时间:2024/05/21 14:59
要提高界面的响应特性,最好的办法莫过于使用多线程,并把呈现界面的线程独立出来。以前只有使用C++才能实现的多线程功能,现在在.Net框架下,所有的语言(包括VB)都可以使用了。不过,使用多线程比使用单一线程要麻烦得多,比如线程之间的同步问题,做得不好很容易出错,而有的时候这种错误要开发人员花上几个星期的时间才能找到。在Windows Form软件中使用多线程更是有一些限制。


0. 在主程序执行一些长时间的耗时操作时候,(比如很多次的循环for(,,), 或者Thread.Sleep(xxx)), UI会没有反应。(因为窗口处理事件是按照消息队列中的顺序来的,没有处理到的就会带在队列里面,其中可能包括界面重绘即响应事件)。

1. 需要提高界面响应,可以使用新的线程来做一些耗时的操作,同时界面保持响应。

2. 耗时操作完成后,使用Control.Invoke/BeginInvoke来更新界面,有同步和异步两个方式,InvokeRequired是用来判断是否需要线程切换(Invoke实际上是把代码切换到主线程,也就是界面线程上面去执行)

3.搞清楚代码到底是在哪个线程上面执行。在new Thread()里面的代码都是在另外的线程上执行
1.Form1.csusing System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading;namespace UpdateUITest{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        private void button1_Click(object sender, EventArgs e)        {            string mnem = this.textBox1.Text.Trim();            //string price = GetPriceUsingNewThread(mnem);            GetPriceUsingNewThread(mnem);        }        private void GetPriceUsingNewThread(string mnem)        {            string price = ServiceProvider.GetPrice2(mnem);                    this.textBox2.Text = price;        }        private void GetPriceUsingNewThread2(string mnem)        {            string price = string.Empty;            new Thread(()=>            {                price = ServiceProvider.GetPrice(mnem);                if (this.InvokeRequired)                {                    this.Invoke(new Action(() =>                        {                            this.textBox2.Text = price;                        }));                }                else                {                    this.textBox2.Text = price;                }            }).Start();        }        private void GetPriceUsingNewThreadInLamda(string mnem)        {            string price = string.Empty;            bool hasGotValue = false;            new Thread(()=>            {                price = ServiceProvider.GetPrice(mnem);                hasGotValue = true;            }).Start();            while (!hasGotValue)            {                Application.DoEvents();            }            this.textBox2.Text = price;        }    }}

2. ServiceProvider.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows.Forms;namespace UpdateUITest{    class ServiceProvider    {        public static string GetPrice(string mnem)        {            string resultPrice;            if (mnem.ToUpper() == "IBM")            {                resultPrice = "10.00";            }            else            {                resultPrice = "20.00";            }            System.Threading.Thread.Sleep(9000);            return resultPrice;        }        public static string GetPrice2(string mnem)        {            string resultPrice;            if (mnem.ToUpper() == "IBM")            {                resultPrice = "10.00";            }            else            {                resultPrice = "20.00";            }            //If you are doing something which would last a long time            //,please give main thread(UI thread) a chance to update itself every other few miliseconds.            for (int i = 0; i < 5000; i++)            {                Application.DoEvents();                System.Threading.Thread.Sleep(2);            }            return resultPrice;        }    }}