[英]Parallel Programming using TPL on WinForms
我試圖在WinForms .NET 4.0上使用TPL,我按照這些步驟(轉到文章末尾)為WPF做了一些小改動,因此它可以在WinForms上工作,但它仍然無法工作..它應該顯示標簽和richTextBox上的結果,但它不...我認為並行處理工作導致鼠標開始移動緩慢一段時間我點擊按鈕..
public static double SumRootN(int root)
{ double result = 0;
for (int i = 1; i < 10000000; i++)
{ result += Math.Exp(Math.Log(i) / root);}
return result;
}
private void button1_Click(object sender, EventArgs e)
{ richTextBox1.Text = "";
label1.Text = "Milliseconds: ";
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
for (int i = 2; i < 20; i++)
{ int j = i;
var t = Task.Factory.StartNew
( () =>
{ var result = SumRootN(j);
Dispatcher.CurrentDispatcher.BeginInvoke
(new Action
( () => richTextBox1.Text += "root " + j.ToString()
+ " " + result.ToString() + Environment.NewLine
)
, null
);
}
);
tasks.Add(t);
}
Task.Factory.ContinueWhenAll
( tasks.ToArray()
, result =>
{ var time = watch.ElapsedMilliseconds;
Dispatcher.CurrentDispatcher.BeginInvoke
( new Action
( () =>
label1.Text += time.ToString()
)
);
}
);
}
您的代碼將無法正常工作,因為顯示結果的線程UI與WPF完全不同。 使用WPF,線程UI是Dispatcher,但在Windows Form上是另一個。
我修改了你的代碼以幫助它工作。
private void button1_Click(object sender, EventArgs e)
{
richTextBox1.Text = "";
label1.Text = "Milliseconds: ";
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
for (int i = 2; i < 20; i++)
{
int j = i;
var t = Task.Factory.StartNew(() =>
{
var result = SumRootN(j);
richTextBox1.Invoke(new Action(
() =>
richTextBox1.Text += "root " + j.ToString() + " "
+ result.ToString() + Environment.NewLine));
});
tasks.Add(t);
}
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
label1.Invoke(new Action(() => label1.Text += time.ToString()));
});
}
暫且不談這樣做是否合適,從學習角度並在評論主題“System.Windows.Threading.Dispatcher和WinForms?”中提到。 有點混亂的答案 :
“如果您確定要在UI線程中(例如,在一個button.Click處理程序中),Dispatcher.CurrentDispatcher將為您提供UI線程調度程序,您可以像往常一樣從后台線程調度到UI線程”
有必要提一下( 也提供了我對上述問題的回答):
Task.Factory.StartNew()
在與主UI或其子線程不同的多個線程上生成執行 System.Windows.Threading.Dispatcher DispatcherObject.Dispatcher
Dispatcher.CurrentDispatcher
正在通過任務非ui線程生成調度程序 無論如何,從對原始WPF代碼進行最小更改的教學觀點來看,您應該已經捕獲並使用了UI調度程序:
private void button1_Click(object sender, EventArgs e)
{ Dispatcher dispatcherUI = Dispatcher.CurrentDispatcher;//added **********
richTextBox1.Text = "";
label1.Text = "Milliseconds: ";
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
for (int i = 2; i < 20; i++)
{ int j = i;
var t = Task.Factory.StartNew
( () =>
{ var result = SumRootN(j);
//Dispatcher.CurrentDispatcher.BeginInvoke//***changed to
dispatcherUI.BeginInvoke
(new Action
( () => richTextBox1.Text += "root " + j.ToString()
+ " " + result.ToString() + Environment.NewLine
)
, null
);
}
);
tasks.Add(t);
}
Task.Factory.ContinueWhenAll
( tasks.ToArray()
, result =>
{ var time = watch.ElapsedMilliseconds;
//Dispatcher.CurrentDispatcher.BeginInvoke//**************changed to
dispatcherUI.BeginInvoke//added
( new Action
( () =>
label1.Text += time.ToString()
)
);
}
);
}
如下面的鏈接所述,正確的方法是完全消除Dispatcher類的使用。相反,您應該創建TaskScheduler的相關實例並將其傳遞給Task方法。 http://blogs.msdn.com/b/csharpfaq/archive/2010/06/18/parallel-programming-task-schedulers-and-synchronization-context.aspx
那是
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
this.Dispatcher.BeginInvoke(new Action(() =>
label1.Content += time.ToString()));
});
會成為
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
label1.Content += time.ToString();
}, CancellationToken.None, TaskContinuationOptions.None, ui);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.