【问题标题】:using PLINQ or Parallel with keeping original order使用 PLINQ 或 Parallel 并保持原始顺序
【发布时间】:2014-01-23 09:19:31
【问题描述】:

我有大量元素。我想为每个元素调用 ToString 并构建一个字符串。 我的第一个方法是放慢速度

        string str = "";
        list.ForEach( g => {

            string s = g.ToString();
            if(s != "")
                str = str + g.ToString() + "\n";
        }); 

我尝试使用 Parallel 类和 PLINQ,如下所示,但最终字符串中元素的顺序与原始字符串不同。

平行

        System.Threading.Tasks.Parallel.ForEach(list, g => {

            string s = g.ToString();
            if(s != "")
                str = str + g.ToString() + "\n";
        });

PLINQ

        string str = "";
        list.AsParallel().AsOrdered().ForAll( g => {

            string s = g.ToString();
            if(s != "")
                str = str + g.ToString() + "\n";
        });

如何提高性能并保持原始顺序? 谢谢

【问题讨论】:

  • AsOrdered() 仅保留原始订单的订单。因此,如果在 ForEach 之后的顺序不同,那么您需要在之后对其进行排序。
  • 我不知道如何保持顺序(或者即使可能),但您应该使用 StringBuilder 而不是连接字符串。
  • 改为使用没有并行的Stringbuilder,它解决了问题。谢谢大家

标签: c# parallel-processing plinq


【解决方案1】:

我认为在这里尝试使用并行不是正确的解决方案,使用更好的算法才是。

目前,您的代码是 O(n2),因为每个连接都会创建一个全新的字符串,因此它必须将整个前一个字符串复制到新的。

但是如果你使用可变的StringBuilder 而不是不可变的string,你可以在 O(n) 时间内做到这一点。这样,您只需在现有 StringBuilder 的末尾追加即可,而无需复制任何内容。

您还可以使用仅用于将字符串连接在一起的特殊方法以更少的代码实现相同的性能:string.Join()


但可能有更好的解决方案:使用StreamWriter。例如,如果您想将生成的字符串写入文件,那将是一个更好的解决方案,因为整个字符串根本不需要在内存中。


并行性不会神奇地解决您的所有性能问题。您需要考虑线程将做什么,特别是如果您有一些共享数据(如代码中的str)。在您的情况下,您可以尝试使用并行,但它不会那么简单,我不确定它是否真的会提高性能。

它的工作原理是这样的:每个线程都会在列表中获取一系列索引并将它们连接起来。最后,主线程会将所有线程的结果连接在一起。但是没有内置的方法,所以你需要自己编写所有代码。 (这可行,因为字符串连接是associative。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    • 2020-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-01
    相关资源
    最近更新 更多