【问题标题】:Plinq Aggregate extension with StringBuilder使用 StringBuilder 的 Plinq 聚合扩展
【发布时间】:2013-12-09 11:23:48
【问题描述】:

我做了一些实验性的 Plinq 查询,但我不确定结果是否会损坏。

这里有 3 种不同的方法,提供相同的结果:

// unitTask is typeof Task<List<SomeEntity>>

        //sequential version PLINQ
        Console.WriteLine(unitTask.Result.Take(10)
           .Aggregate(new StringBuilder(),
           (text, current) => text.AppendFormat("@{0}sa{1}", 
               current.FullName.Substring(0, 3), 
               current.FullName.Substring(4)))
           .ToString());

        //parallel version PLINQ
        Console.WriteLine(unitTask.Result.Take(10).AsParallel()
            .Aggregate(new StringBuilder(),
            (text, current) => text.AppendFormat("@{0}sa{1}",
                current.FullName.Substring(0, 3),
                current.FullName.Substring(4)))
            .ToString());

        //parallel version foreach with Partitioner
        var output = new StringBuilder();
        Parallel.ForEach(Partitioner.Create(unitTask.Result.Take(10)), r =>
        {
            //Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            output.AppendFormat("@{0}sa{1}", r.FullName.Substring(0, 3), 
                r.FullName.Substring(4));
        });

        Console.WriteLine(output.ToString());

我的问题是:

我可以在 PLINQ 中使用StringBuilder 吗? 据我所知,由于 append 方法不是线程安全的。

或者在这种情况下它是否以顺序模式运行?

Parallel.Foreach 在不同线程中运行查询,但结果与顺序 Plinq 相同。

它是偶然的,还是它很聪明并且使用了一些同步?

【问题讨论】:

    标签: c# stringbuilder plinq


    【解决方案1】:
    1. 这个版本不使用PLINQ,它使用标准的LINQ,所以很安全。

    2. 此版本使用不能安全并行化的Aggregate() 重载,因此它也将在单个线程上执行。这意味着它是安全的,但也不会比顺序版本快。

      要真正利用 PLINQ,您需要使用实际上可以并行执行的another overload of Aggregate()。在您的情况下,这意味着每个线程都有一个单独的StringBuilder,然后将所有StringBuilders 合并为一个。比如:

      input.AsParallel().Aggregate(
          () => new StringBuilder(),
          (text, current) => text.AppendFormat("@{0}", current.FullName),
          (text1, text2) => text1.Append(text2),
          text => text.ToString())
      

      这假设您不关心最终字符串中元素的顺序。否则,此代码将无法正常工作。

    3. 此代码从多个线程修改相同的StringBuilder 对象。 StringBuilder 不是线程安全的,所以这段代码不安全。

    【讨论】:

    • 经过进一步调查和测量,我得到了类似的结果(单线程并且比纯顺序 linq 慢)。感谢您的确认,以及替代方案。
    【解决方案2】:

    这是偶然的,可能是因为代码没有做那么多,并且可能在单个线程上运行。您的所有电话都涉及unitTask.Result,它会阻塞直到unitTask 完成。所有的 sn-ps 实际上只适用于顺序生成的 10 个实体,因此没有足够的数据来证明并行执行的合理性

    三个 sn-ps 做不同的事情:

    1. 第一个 sn-p 只是按顺序处理 10 个 sn-ps 的列表。
    2. PLINQ 版本采用包含 10 个实体的列表,但不并行执行任何操作。即使是这样,对 Aggregate 的调用也会收集所有工作人员的结果并按顺序处理它们以创建最终结果。
    3. 第三个 sn-p 可以显示并行行为,因为它并行执行一个动作块。再次,结果数量太少,只使用了一个线程

    【讨论】:

    • 第三个 sn-p 为我使用了 4 个线程。在这种情况下,简单的字符串对象是更好的选择?
    • 我的意思是你在比较不同的东西。这与线程安全无关。即使您连接字符串,也会得到不一致的结果,因为每个线程在每次迭代时都会看到不同的输入字符串。你到底想解决什么问题?如果你想记录进度,Console.WriteLine 绰绰有余
    • 正如我所写,这是一项实验性任务,旨在了解这些组件的工作原理。我不想解决任何事情。只是比较顺序和并行执行。所以你说并行连接字符串不是一个好主意。
    猜你喜欢
    • 2011-01-20
    • 1970-01-01
    • 1970-01-01
    • 2023-02-25
    • 1970-01-01
    • 1970-01-01
    • 2017-01-02
    • 1970-01-01
    • 2012-12-25
    相关资源
    最近更新 更多