我有一个简单的应用程序会告诉我一个范围内的素数数量:
private void btnMultiThread_Click(object sender, RoutedEventArgs e)
{
var numbers = Enumerable.Range(2, range - 1);
var totalPrimes = numbers
.AsParallel()
.Where(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i != 0))
.Count();
MessageBox.Show(totalPrimes.ToString());
}
问题是,虽然整个事情都在计算,但是wpf应用程序仍然没有响应:例如,我点击的按钮仍然被推入,应用程序窗口无法移动甚至关闭。
我该怎么做才能解决这个问题? 感谢
答案 0 :(得分:5)
这不是关于多线程本身。 Parallel
和PLINQ使用多个线程包括当前的线程并行处理数据。如果你想避免阻塞,你必须在后台任务中执行PLINQ查询,例如使用Task.Run:
private async void btnMultiThread_Click(object sender, RoutedEventArgs e)
{
var numbers = Enumerable.Range(2, range - 1);
var totalPrimes = await Task.Run(()=>
numbers
.AsParallel()
.Where(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i != 0))
.Count());
MessageBox.Show(totalPrimes.ToString());
}
或使其更清洁:
private async void btnMultiThread_Click(object sender, RoutedEventArgs e)
{
var numbers = Enumerable.Range(2, range - 1);
var totalPrimes = await Task.Run(()=>CalculatePrimes(numbers));
MessageBox.Show(totalPrimes.ToString());
}
private int CalculatePrimes(IEnumerable<int> numbers)
{
return numbers
.AsParallel()
.Where(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i != 0))
.Count());
}
答案 1 :(得分:2)
Microsoft摘自Chaining Tasks by Using Continuation Tasks:
在异步编程中,一个异步非常常见 完成时的操作,以调用第二个操作并传递数据 它。传统上,这是通过使用回调方法完成的。在 任务并行库,提供相同的功能 延续任务。延续任务(也称为 continuation)是由另一个任务调用的异步任务, 当前因完成时,它被称为 antecedent 。
这是一种方式:
private void btnMultiThread_Click(object sender, RoutedEventArgs e)
{
Task<int>.Factory.StartNew(() =>
{
var numbers = Enumerable.Range(2, range - 1);
var totalPrimes = numbers
.AsParallel()
.Where(n => Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i != 0))
.Count();
return totalPrimes;
}).ContinueWith(() => MessageBox.Show(antecendent.Result.ToString()); // Antecedent result feeds into continuation
}