2011-10-02 22 views
3

當我使用如下所示的AddListBoxItem函數內的調用軟件變得反應遲鈍和凍結,但如果我使用BeginInvoke它的工作原理。爲什麼會發生?當使用並行BeginInvoke工作,而調用不是 - c#4.0

Visual Studio 2010中,C#4.0

private void button2_Click(object sender, EventArgs e) 
{ 
    var watch = Stopwatch.StartNew(); 
    Parallel.For(2, 20, (i) => 
    { 
     var result = SumRootN(i); 
     AddListBoxItem("root " + i + " : " + result); 
    }); 
    AddListBoxItem(watch.ElapsedMilliseconds.ToString());    
} 

private delegate void AddListBoxItemDelegate(object item); 

private void AddListBoxItem(object item) 
{ 
    if (this.listBox1.InvokeRequired) 
    { 
     this.listBox1.Invoke(new AddListBoxItemDelegate(this.AddListBoxItem), item); 
    } 
    else 
    { 
     this.listBox1.Items.Add(item); 
    } 
} 

回答

3

你的UI線程等待Parallel.For完成後再繼續。這意味着它不能處理任何進一步的UI消息,直到它完成。

現在,當工作程序線程調用Invoke時,它們將等待UI線程處理委託,然後才繼續。所以他們正在等待UI線程獲得免費,基本上。

因此,你有一個僵局 - UI線程在等待任務,正在等待UI線程... BeginInvoke作品,因爲這樣的任務線程等待在處理代表UI線程。

我建議你不要在UI線程中調用Parallel.For開始。無論如何,你會阻止用戶界面,直到它完成,這不是一個好主意。在後臺線程中完成整個任務 - 如果需要,您仍然可以使用Invoke,並且在執行計算時UI仍然會響應。

+0

我怎麼能在不同的線程中調用它?我的意思是調用parallel.for? – MonsterMMORPG

+0

@MonsterMMORPG:從其他任何線程* BackgroundWorker或使用ThreadPool.QueueUserWorkItem - 甚至Task.Factory.StartNew,從另一個線程執行*整件事*。 –

+0

我認爲任務是更好的感謝回答。現在我明白了爲什麼變得沒有反應:) – MonsterMMORPG

1

我認爲這是因爲Mainthread beeing在上面的Click事件中被阻塞,等待完成AddListBoxItem,它正在等待buttion2_click事件返回。
您的UI中不應該有Controller邏輯,因此Click不會在不同線程中調用邏輯的主要問題。

爲您的邏輯實現一個線程後,您的GUI不會阻塞,並且在任何情況下都會輕鬆刷新。

3

這聽起來像你是UI線程死鎖。這是非常有意義的,因爲button2_Click直到For完成纔會退出,而特別是,直到button2_Click完成後才能處理消息循環事件。如果您處於不同的線程,則Invoke使用消息循環事件,並且在處理該項目之前不會返回 - 因此不會執行任何操作 - 並且For/button2_Click將永遠不會完成。

通過使用BeginInvoke您只需隊列這項工作 - BeginInvoke立即返回。這意味着For可以完成,它允許完成button2_Click,其中然後允許處理消息循環事件(更新UI)。