【问题标题】:C# multithreaded merging of big number of XML documents大量 XML 文档的 C# 多线程合并
【发布时间】:2023-03-13 22:28:01
【问题描述】:

我有一些合并 XML 文档的代码。它可以根据需要合并任意数量的文档,但是一旦数量开始增加,它就会变得有点慢。

    private string MergeList(List<string> documents)
    {
        string result = string.Empty;

        for (int i = 0; i < documents.Count; i++)
        {
            switch (i)
            {
                case 0: // Do nothing on first elapse
                    break;
                case 1: // Use first and second
                    result = Merge(documents[0], documents[i]);
                    break;
                default: // Now just keep merging until no more documents in list
                    result = Merge(result,documents[i]);
                    break;
            }
        }

        return result;
    } 

有没有什么聪明的方法来做这个多线程?我需要做的就是最终将所有文档合并到同一个字符串中。它们合并的顺序无关紧要。

我可以想象一定有某种模式可以做到这一点?

【问题讨论】:

  • Merge 是做什么的?简单的字符串连接还是更复杂的东西?
  • 从索引 1 而不是 0 开始循环怎么样?
  • 它合并了两个 XML 文档——不是火箭科学合并——但也不仅仅是简单的串联。查找存在于其中一个而不存在于另一个中的元素,更改一些引用等。
  • Scoregraphic - 好点,但这对我的整体问题没有帮助。
  • 这就是我添加它作为评论的原因 ;-)

标签: c# multithreading design-patterns merge parallel-processing


【解决方案1】:

为简单起见,假设您有一些合并功能(这里只是连接,您当然可以在这里进行 XML 处理等):

public static string Merge(string a, string b)
{
    return a + b;
}

您可以通过将输入集合分成两个并递归合并它们来通过递归创建一组Task&lt;&gt;。可以看作是创建Tasks等待图

public static async Task<string> MergeRecursive(IEnumerable<string> strings)
{
    if (strings.Count() == 1)
        return strings.First();
    // Here we make a real merging
    if (strings.Count() == 2)
        return Merge(strings.First(), strings.Last());

    var parts = strings.Select((s, i) => new { s, i })
                       .GroupBy(g => g.i % 2, g => g.s, (k, v) => v)
                       .ToList();
    var results = await Task.WhenAll(parts.Select(p => Task.Run(() => MergeRecursive(p))));
    return await MergeRecursive(results);
}

那么你就可以得到结果:

List<string> documents = new List<string>();
for (int i = 0; i < 100000; ++i)
    documents.Add(i.ToString("X"));

var merge = MergeRecursive(documents).Result;    

对于这种情况,Concurrency Visualizer 显示 5 个工作的 CLR 线程并行进行合并。

【讨论】:

  • 这看起来就像我正在寻找的 - 我会测试它并返回。
  • 如果文档数量为奇数,会发生什么?如果将一个文档分配给另外两个文档,则必须确保 Merge() 是线程安全的。
  • @C4stor,首先if 负责处理奇数文档的子集合
  • 啊,这是 .net 4.5 我正在使用 4.0。但由于我控制了这一切,也许我应该考虑切换到 4.5。
  • 我得到一个 StackOverflowException 你的: var parts = strings.Select((s, i) => new { s, i }) .GroupBy(g => gi % 2, g => gs , (k, v) => v) .ToList();
【解决方案2】:

一种简单的方法是将List&lt;string&gt; 文档设置为全局并添加BackgroundWorker 并将事件DoWork 设置为将文档和事件RunWorkCompleted 合并到程序末尾的函数。

【讨论】:

    【解决方案3】:

    如果您所做的只是将字符串连接在一起,那么多线程可能是矫枉过正。相反,使用 StringBuffer 并预先计算大小以避免内存重新分配:

    private string MergeList(List<string> documents)
    {
      int size=0;
    
      foreach(var doc in documents)
      {
        size+=doc.Length;
      }
    
      StringBuffer buffer = new StringBuffer(size);
    
      foreach(var doc in documents)
      {
        buffer.append(doc);
      }
    
      return buffer.ToString();
    }
    

    【讨论】:

    • 它比字符串连接更复杂。它合并两个文档中的元素,更改引用等。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-28
    相关资源
    最近更新 更多