BeginInvoke 方法真的是新開一個線程進行異步調用嗎?編程
參考如下代碼:安全
public delegate void treeinvoke(); private void UpdateTreeView() { MessageBox.Show(System.Threading.Thread.CurrentThread.Name); } private void button1_Click(object sender, System.EventArgs e) { System.Threading.Thread.CurrentThread.Name = "UIThread"; treeView1.BeginInvoke(new treeinvoke(UpdateTreeView)); }
看看運行結果,彈出的對話框中顯示的是 UIThread,這說明 BeginInvoke 所調用的委託根本就是在 UI 線程中執行的。多線程
既然是在 UI 線程中執行,又何來「異步執行」一說呢?異步
咱們再看看下面的代碼:this
public delegate void treeinvoke(); private void UpdateTreeView() { MessageBox.Show(Thread.CurrentThread.Name); } private void button1_Click(object sender, System.EventArgs e) { Thread.CurrentThread.Name = "UIThread"; Thread th = new Thread(new ThreadStart(StartThread)); th.Start(); } private void StartThread() { Thread.CurrentThread.Name = "Work Thread"; treeView1.BeginInvoke(new treeinvoke(UpdateTreeView)); }
再看看運行結果,彈出的對話框中顯示的仍是 UIThread,這說明什麼?這說明 BeginInvoke 方法所調用的委託不管如何都是在 UI 線程中執行的。線程
那 BeginInvoke 究竟有什麼用呢?orm
在多線程編程中,咱們常常要在工做線程中去更新界面顯示,而在多線程中直接調用界面控件的方法是錯誤的作法,具體的緣由能夠在看完個人這篇以後看看這篇:在多線程中如何調用Winform,若是你是大牛的話就不要看我這篇了,直接看那篇吧,反正那篇文章我沒怎麼看懂。blog
Invoke 和 BeginInvoke 就是爲了解決這個問題而出現的,使你在多線程中安全的更新界面顯示。io
正確的作法是將工做線程中涉及更新界面的代碼封裝爲一個方法,經過 Invoke 或者 BeginInvoke 去調用,二者的區別就是一個致使工做線程等待,而另一個則不會。form
而所謂的「一面響應操做,一面添加節點」永遠只能是相對的,使 UI 線程的負擔不至於太大而以,由於界面的正確更新始終要經過 UI 線程去作,咱們要作的事情是在工做線程中包攬大部分的運算,而將對純粹的界面更新放到 UI 線程中去作,這樣也就達到了減輕 UI 線程負擔的目的了。
而在那段更新樹節點的代碼中,其實惟一塊兒做用的代碼是:System.Threading.Thread.Sleep(100);,它使 UI 線程有了處理界面消息的機會,其實將問題複雜化了,只要如下的代碼就能夠很好的工做了。
private void button1_Click_(object sender, System.EventArgs e) { TreeNode tn; for(int i=0;i<100000;i++) { tn=new TreeNode (i.ToString()); this.treeView1.Nodes[0].Nodes.Add(tn); if (i%100 == 0) Application.DoEvents(); } }