網友問題,這裡大概簡單實作並記錄。
一般初期大家都以單執行緒為主,但後期需求變多或要處理大量耗時作業
單一執行緒幾乎無法滿足我們的需求,而且還會被使用者抱怨程式用起來很卡或無回應(看個人造化!遇到好user算祖上積德XD)。
遇到這樣的狀況,大多使用者都會強制關閉程式(UI執行緒在沒把主控權交還給Windows前是凍結的)
使用單一執行緒幾乎都躲不了這樣的宿命,所以就得靠多執行緒來改善這樣的問題。
行為:執行大量新增作業(100000筆資料)
初始畫面
01 | DataTable dt; |
02 | bool flag; |
03 | private void Form1_Load( object sender, EventArgs e) |
04 | { |
05 | InitData(); |
06 | ThreadPool.SetMinThreads(2, 5); |
07 | ThreadPool.SetMaxThreads(4, 10); |
08 | } |
09 |
10 |
11 | private void InitData() |
12 | { |
13 | dt = new DataTable( "table1" ); |
14 | dt.Columns.Add( "c1" ); |
15 | dt.Columns.Add( "c2" ); |
16 | Random rnd = new Random(); |
17 | for (Int32 i = 1; i <= 10; i++) |
18 | { |
19 | DataRow row = dt.NewRow(); |
20 | row[ "c1" ] = rnd.Next(1, 100); |
21 | row[ "c2" ] = "i_am_c2" ; |
22 | dt.Rows.Add(row); |
23 | } |
24 | dataGridView1.DataSource = dt; |
25 | } |
單一執行緒(新增資料)
01 | private void button1_Click( object sender, EventArgs e) |
02 | { |
03 | flag = true ; |
04 | //單一執行緒 |
05 | AddRow(); |
06 | //將job丟入ThreadPool Queue |
07 | //主緒繼續處理畫面 |
08 | //ThreadPool.QueueUserWorkItem(new WaitCallback(AddRow)); |
09 | } |
10 |
11 | private void AddRow() |
12 | { |
13 | if (flag) |
14 | { |
15 | for (Int32 i = 1; i <= 100000; i++) |
16 | { |
17 | DataRow dr = dt.NewRow(); |
18 | dr[ "c1" ] = i.ToString(); |
19 | dr[ "c2" ] = "hello" ; |
20 | dt.Rows.Add(dr); |
21 | label1.Text = "總共筆數:" + dt.Rows.Count.ToString(); |
22 | if (i % 500 == 0) |
23 | { |
24 | dataGridView1.FirstDisplayedScrollingRowIndex = dt.Rows.Count; |
25 | } |
26 | } |
27 | } |
28 | else |
29 | return ; |
30 | } |
執行畫面果然完全凍結,而且畫面也無法重畫(一片白),這時任誰都會想按下ctrl+alt+del。
使用ThreadPool來改善
01 | private void button1_Click( object sender, EventArgs e) |
02 | { |
03 | flag = true ; |
04 | //單一執行緒 |
05 | //AddRow(); |
06 | //將job丟入ThreadPool Queue |
07 | //主緒繼續處理畫面 |
08 | ThreadPool.QueueUserWorkItem( new WaitCallback(AddRow)); |
09 | } |
10 |
11 | //宣告delegate |
12 | delegate void MyInvoke(String status); |
13 | private void UpdateLab(String status) |
14 | { |
15 | label1.Text = status; |
16 | } |
17 |
18 | delegate void MyInvoke2(Int32 index); |
19 | private void DisplayDataGridView(Int32 index) |
20 | { |
21 | dataGridView1.FirstDisplayedScrollingRowIndex = index; |
22 | } |
23 |
24 | private void AddRow( object arg) |
25 | { |
26 | if (flag) |
27 | { |
28 | for (Int32 i = 1; i <= 100000; i++) |
29 | { |
30 | DataRow dr = dt.NewRow(); |
31 | dr[ "c1" ] = i.ToString(); |
32 | dr[ "c2" ] = "hello" ; |
33 | dt.Rows.Add(dr); |
34 | MyInvoke mi = new MyInvoke(UpdateLab); |
35 | //使用主緒更新Label |
36 | Invoke(mi, "總共筆數:" + dt.Rows.Count.ToString()); |
37 | Thread.Sleep(1); |
38 | if (i % 500 == 0) |
39 | { |
40 | MyInvoke2 mi2 = new MyInvoke2(DisplayDataGridView); |
41 | //使用主緒更新DataGridView |
42 | Invoke(mi2,i); |
43 | } |
44 | } |
45 | } |
46 | else |
47 | return ; |
48 | } |
使用ThreadPool後,UI終於可隨意拖拉,UI裡的物件也可即時重畫,在也不會發生無回應或很卡的狀況了。
联系客服