程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> Control.CheckForIllegalCrossThreadCalls=false不可在多線中隨便使用

Control.CheckForIllegalCrossThreadCalls=false不可在多線中隨便使用

編輯:.NET實例教程

CodeProject上有篇文章An Alternate Way of Writing a Multithreaded GUI in C#

本意是Alternate Way 另外一種方法,後來莫名其妙的被轉載成中文變了題目,最高效的方法。

        CheckForIllegalCrossThreadCalls和control.Invoke有什麼不同,哪個更好用,更高效呢?
        占在任何角度講,都不要使用CheckForIllegalCrossThreadCalls,即便他運行和代碼編寫的確實比Invoke效率高
        感興趣的,可以參考我後面貼出的代碼來測試對比一下兩者的不同。這裡我只簡單說一下結論:
        1、性能CheckForIllegalCrossThreadCalls=false時比invoke高,而且代碼比較優雅。
        測試時間如下:
        Button1 ---------------------------
        00:00:01.0760900
        00:00:01.0771200
        Button2 --------------------------
        00:00:01.0812499
        00:00:01.0813443
        效率差多少?在這裡時間還不到1%,代碼少寫一個if字句
        看到有文章說這種方法在大量更新ui時會引發大量異常,導致性能下降
        我測試了一下,耗時和循環次數是很平穩的線性關系,而且也沒有發現幾個Exception相關性能計數器有問題,這說明這又是某老外朋友想當然的說法。

        2、CheckForIllegalCrossThreadCalls在.net1.x中默認是false,也就是不檢查,.Net2.0和3.x默認是true
        說明這是ms有意的引導,說不定以後不讓你改了。這也是很多1.x用戶在剛用2.0時不習慣跨線程更新ui的原因之一。

        3、死穴:安全性
        CheckForIllegalCrossThreadCalls容許子線呈隨時更新ui,在同一個test函數體內,不能保證自身事務的一致性。給label1付了值
        一回頭,就已經被別人改了,這和超市的踩踏事件的後果一樣嚴重。
        當然你可以自己加鎖,用信號量,這樣還不如直接使用Invoke了,你只是又把別人做好的事情做了一遍。

        如果你覺的你的應用不會考慮在寫入ui的同時來讀取ui,而傾向使用CheckForIllegalCrossThreadCalls來追求效率的話,也是不恰當的做法。
        首先CheckForIllegalCrossThreadCalls並不能讓效率發生本質的變化。
        其次需求永遠是變化的,現在不考慮不等於以後不會碰到
        聽從ms的引導。否則以後要在高版本的.Net framework中移植代碼的時候需要花費數倍的人工。



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication34
...{
    public partial class Form1 : Form
    ...{
        public Form1()
        ...{
            InitializeComponent();
        }



        //模擬一個實際應用
        //對label1付值後立馬檢查他的值,如果已經被改過則拋出異常

        void test()
        ...{
            string strText = Guid.NewGuid().ToString();
            this.label1.Text = strText;
            if (this.label1.Text != strText)
            ...{
                //測試性能時把這一句注釋掉!!!!!!!!!!!!!!!!!!!!!!1
                throw new Exception("label1的值意外改變");
            }
        }

        //不使用invoke方法直接進入Control
        void doThread()
        ...{
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Reset();
            sw.Start();
            for (int i = 0; i < 100; i++)
            ...{
                test();
                System.Threading.Thread.Sleep(10);
            }
            sw.Stop();
            Console.WriteLine(sw.Elapsed);
        }

        //使用invoke方法
        public delegate void dTest();
        void invokeThread()
        ...{
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Reset();
            sw.Start();
            for (int i = 0; i < 100; i++)
            ...{
                if (this.InvokeRequired)
                ...{
                    this.Invoke(new dTest(test));
                }
                else
                ...{
                    test();
                }
                System.Threading.Thread.Sleep(10);
            }
            sw.Stop();
            Console.WriteLine(sw.Elapsed);
        }


        //通過CheckForIllegalCrossThreadCalls的值忽略跨線程錯誤,這時會拋出異常
        private void button1_Click(object sender, EventArgs e)
...{
            Form1.CheckForIllegalCrossThreadCalls = false;
            new System.Threading.Thread(new System.Threading.ThreadStart(doThread)).Start();
            new System.Threading.Thread(new System.Threading.ThreadStart(doThread)).Start(); 
            
        }
        //通過invoke方法,在主線程排隊,lable1的值在test函數體內永遠是線程安全的.
        private void button2_Click(object sender, EventArgs e)
        ...{
            new System.Threading.Thread(new System.Threading.ThreadStart(invokeThread)).Start();
            new System.Threading.Thread(new System.Threading.ThreadStart(invokeThread)).Start();
        }
    }
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved