使用PLINQ或Parallel保持原始顺序

时间:2014-01-23 09:19:31

标签: c# parallel-processing plinq

我有很多元素。我想为每个元素调用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";
        });

如何提高性能并保持原始订单? 感谢

1 个答案:

答案 0 :(得分:0)

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

目前,您的代码为O n 2 ),因为每个连接都会创建一个全新的字符串,因此必须复制整个以前的字符串进入新的。

但如果使用可变StringBuilder而不是不可变string,则可以使用O(n)进行此操作。这样,您可以在现有StringBuilder的末尾追加,而不必复制任何内容。

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


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


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

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