C# Parallel.ForEach对于DataTable工作太慢

C# Parallel.ForEach对于DataTable工作太慢,c#,foreach,datatable,parallel-processing,parallel.foreach,C#,Foreach,Datatable,Parallel Processing,Parallel.foreach,我在DTable中实现Parallel.ForEach时遇到问题。以下是我正在实现的示例代码: Parallel.ForEach(dTable4.AsEnumerable(), row4 => { string getCondition = row4[1].ToString(); getCondition = EvaluateCondExpression(getCondition); //Evalua

我在DTable中实现Parallel.ForEach时遇到问题。以下是我正在实现的示例代码:

Parallel.ForEach(dTable4.AsEnumerable(), row4 =>
            {
                string getCondition = row4[1].ToString();
                getCondition = EvaluateCondExpression(getCondition);  //Evaluates CM for value (CM1==2 && CM2<5);
                Expression e = new Expression(getCondition); //getCondition = (2==2 && 2<5)
                var evalutateCondition = e.Evaluate();
                if (Convert.ToBoolean(evalutateCondition))
                {
                   //Write string to TextBox
                }
             }

串行ForEach计算占用了太多的时间,所以我想应用Parallel.ForEach迭代,但不幸的是它不起作用。有谁能建议我如何最大限度地提高性能,以及我在并行过程中犯了哪些错误。ForEach。

运行一次循环迭代需要多长时间?您正在运行多少次迭代?通常,Parallel.Foreach非常适合在每次迭代可能需要相当长时间的循环中运行。相反,如果您有一个相对快速的操作的多次迭代,您将花费大量额外的开销来生成和管理线程,这可能就是您所看到的。有关此类场景的更多信息,请参阅本MSDN文章:

更新


是Parallel.Foreach和await Task.whalll的一个很好的比较。

运行一次循环迭代需要多长时间?您正在运行多少次迭代?通常,Parallel.Foreach非常适合在每次迭代可能需要相当长时间的循环中运行。相反,如果您有一个相对快速的操作的多次迭代,您将花费大量额外的开销来生成和管理线程,这可能就是您所看到的。有关此类场景的更多信息,请参阅本MSDN文章:

更新


是Parallel.Foreach和await Task.whalll的一个很好的比较。

使用传统的Foreach,将每个迭代包装到一个任务中,您可能会看到性能的提高。将每次迭代的任务添加到集合中,然后添加到foreach调用任务之外。WhenAlltasks;如果有什么好处的话,它可以让您等待昂贵的并行处理

您可以将Parallel.ForEach的内容转换为Select Linq查询,该查询将每个迭代转换为一个任务。生成的任务集合可以提供给Task.WhenAll方法等待

await Task.WhenAll(dtable4.AsEnumerable().Select(row4 => new Task(() =>
{
    string getCondition = row4[1].ToString();
    getCondition = EvaluateCondExpression(getCondition);  //Evaluates CM for value (CM1==2 && CM2<5);
    Expression e = new Expression(getCondition); //getCondition = (2==2 && 2<5)
    var evalutateCondition = e.Evaluate();
    if (Convert.ToBoolean(evalutateCondition))
    {
        //Write string to TextBox
    }
})));

这可能无法解决您所看到的性能瓶颈,但至少可以让您等待并行进程并释放UI线程。

使用传统的foreach,将每个迭代包装到一个任务中,您可能会看到性能的提高。将每次迭代的任务添加到集合中,然后添加到foreach调用任务之外。WhenAlltasks;如果有什么好处的话,它可以让您等待昂贵的并行处理

您可以将Parallel.ForEach的内容转换为Select Linq查询,该查询将每个迭代转换为一个任务。生成的任务集合可以提供给Task.WhenAll方法等待

await Task.WhenAll(dtable4.AsEnumerable().Select(row4 => new Task(() =>
{
    string getCondition = row4[1].ToString();
    getCondition = EvaluateCondExpression(getCondition);  //Evaluates CM for value (CM1==2 && CM2<5);
    Expression e = new Expression(getCondition); //getCondition = (2==2 && 2<5)
    var evalutateCondition = e.Evaluate();
    if (Convert.ToBoolean(evalutateCondition))
    {
        //Write string to TextBox
    }
})));

这可能无法解决您所看到的性能瓶颈,但至少可以让您等待并行进程并释放UI线程。

在使用parallel.ForEach时,您可以对代码进行以下修改,尤其是对于长时间运行的任务

Parallel.ForEach( dTable4.AsEnumerable(), new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount}, row4 = >
这将确保Parallel.ForEach不会启动datatable中每个数据点的线程,它只会根据环境处理器/内核的数量动态生成线程,从而减少争用和线程上下文切换。然而,理想情况下,正如上面所建议的,您可以为长时间运行的任务规划异步模式


正如我看到的,您正在并行循环内更新UI控件,因此您无论如何都需要UI线程上下文,否则它将是一个异常。Async Anway在UI线程上下文中运行

使用Parallel.ForEach时,特别是对于长时间运行的任务,可以对代码进行以下修改

Parallel.ForEach( dTable4.AsEnumerable(), new ParallelOptions {MaxDegreeOfParallelism = Environment.ProcessorCount}, row4 = >
这将确保Parallel.ForEach不会启动datatable中每个数据点的线程,它只会根据环境处理器/内核的数量动态生成线程,从而减少争用和线程上下文切换。然而,理想情况下,正如上面所建议的,您可以为长时间运行的任务规划异步模式


正如我看到的,您正在并行循环内更新UI控件,因此您无论如何都需要UI线程上下文,否则它将是一个异常。异步运行在UI线程上下文中

通过使用传统的foreach,将每个迭代包装到一个任务中,您可能会看到性能的提高。将每次迭代的任务添加到集合中,然后添加到foreach调用任务之外。WhenAlltasks;如果它让你有能力等待昂贵的并行处理。你能给我提供任何链接作为参考。显示性能改进的参考?或链接显示一个这样做的例子?在一个任务中包装每一次迭代的引用。对于长时间运行的任务,超过2-3秒的任何事情都考虑使用异步等待,而不是并行。事实上,Async-Await甚至不像并行调用那样阻塞。通过使用传统的foreach,将每个迭代包装到一个任务中,您可能会看到性能的提高。将每个迭代的任务添加到集合中,然后将其添加到foreach调用任务的外部。WhenAllt

问;如果它让你有能力等待昂贵的并行处理。你能给我提供任何链接作为参考。显示性能改进的参考?或链接显示一个这样做的例子?在一个任务中包装每一次迭代的引用。对于长时间运行的任务,超过2-3秒的任何事情都考虑使用异步等待,而不是并行。事实上,Async-Await甚至不像Parallel callSize那样阻塞,迭代的大小取决于用户选择参数,但为了测试,我考虑了第一个Parallel.ForEach函数的7个循环,该函数在串行ForEach操作中运行约5596ms,并行ForEach操作中运行约12879ms。我希望提高性能,因为在处理许多迭代时,它将以指数形式滞后。迭代大小可能会达到20~25个循环,这可能会迫使用户等待超过15~20Sec的时间。Parallel.Foreach不适合建议的长时间运行的任务,事实上,如果每个并行线程都有一个长时间的任务,那么会导致更多的上下文切换和争用,因为它们会使内核在更长的时间内处于繁忙状态,当其他线程尝试使用它时,对于长时间运行的任务来说,Async-Await是更好的选择,事实上它甚至不像Paralel那样阻塞。ForEach@sk3145您可能需要花一些时间进行基准测试。尝试以下我提供的MSDN链接中的示例。与另一个答案一样,Parallel.ForEach有几个选项可用于调整生成的线程数量和其他一些内容,所有这些都可以通过浏览MSDN文章找到。如果不尝试不同的方法,很难准确地说什么能让它表现得最好。迭代的大小取决于用户选择的参数,但为了测试,我考虑了第一个Parallel.ForEach函数的7个循环,在串行ForEach操作和并行ForEach操作中运行大约需要5596ms。ForEach大约需要12879ms执行相同的任务。我希望提高性能,因为在处理许多迭代时,它将以指数形式滞后。迭代大小可能会达到20~25个循环,这可能会迫使用户等待超过15~20Sec的时间。Parallel.Foreach不适合建议的长时间运行的任务,事实上,如果每个并行线程都有一个长时间的任务,那么会导致更多的上下文切换和争用,因为它们会使内核在更长的时间内处于繁忙状态,当其他线程尝试使用它时,对于长时间运行的任务来说,Async-Await是更好的选择,事实上它甚至不像Paralel那样阻塞。ForEach@sk3145您可能需要花一些时间进行基准测试。尝试以下我提供的MSDN链接中的示例。与另一个答案一样,Parallel.ForEach有几个选项可用于调整生成的线程数量和其他一些内容,所有这些都可以通过浏览MSDN文章找到。很难确切地说,如果不尝试不同的东西,什么会使它运行得最好。这是个好主意,你可以检查并行度是否有帮助,否则这是一种方法,尤其是如果你需要调用非阻塞的话,他也应该考虑不写到UI,直到所有的完成。因此,每个任务都不会切换到UI同步上下文进行写入。如果您使用的是任何绑定,那么写入UI的开销都很高,因为所有绑定都必须刷新。他没有指定他的UI框架,所以OP将不得不使用他的离散。这是一个好主意,你可以检查并行度是否有帮助,否则这将是一种方法,尤其是如果你需要调用非阻塞的话,他也应该考虑不写UI,直到完成时,因此,每个任务都不会切换到UI同步上下文进行写入。如果您使用的是任何绑定,那么写入UI的开销都很高,因为所有绑定都必须刷新。他没有指定UI框架,因此OP将不得不自行决定