我如何实现该应用程序仍然响应,而线程在后台工作?

时间:2017-01-03 09:44:48

标签: c# wpf linq

我有一个简单的应用程序会告诉我一个范围内的素数数量:

    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应用程序仍然没有响应:例如,我点击的按钮仍然被推入,应用程序窗口无法移动甚至关闭。

我该怎么做才能解决这个问题? 感谢

2 个答案:

答案 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
}