【问题标题】:Multiple Threads to load xml files into memory多线程将xml文件加载到内存中
【发布时间】:2011-09-11 08:19:54
【问题描述】:

我有一组 XML 文件,我想加载到内存中以便处理。

我正在将文件加载到集合中,如果我在单个线程中加载文件而不是使用线程池,它似乎要快得多。

我原以为情况会相反。

为什么使用多个线程将文件加载到内存中比我只遍历文件列表并在单个线程上一个接一个地加载每个文件要慢得多?

这是 C# .net 3.5

代码:

ICollection<XmlDocument> xmlFilesToProcess = new Collection<XmlDocument>();

foreach (FileInfo fileInfo in fileList)
{
     ThreadPool.QueueUserWorkItem(
        (o) =>
        {
            XmlDocument doc = new XmlDocument();
            doc.Load((string)o);
            lock (xmlFilesToProcess)
            {
                xmlFilesToProcess.Add(doc);
                counter++;
            }
        }, fileInfo.FullName);
}

【问题讨论】:

    标签: c# multithreading performance file


    【解决方案1】:

    没有看到代码,很难说。如果 XML 的大小和/或数量很小并且您只有一个 CPU,那么可能只是线程之间的上下文切换所花费的时间比读取文件所需的时间要长。

    编辑

    现在我看到您创建的线程太多了。我建议你使用 TPL 的 Parallel.For。这适用于 .Net 3.5

    有关 TPL 的更多信息,请参阅 http://msdn.microsoft.com/en-us/magazine/cc163340.aspx。

    【讨论】:

    • xml 文件相对较小(在 10k - 500k 之间)但数量很大(>10,000)
    • 您创建的线程太多。与实际的 XML 处理相比,创建线程/上下文切换所花费的时间更多。
    • Parallel.For 内部不使用线程池吗?我的理解是 ThreadPool.QueueUserWorkItem 实际上并没有创建另一个线程,它只是创建了一个将由 ThreadPool 处理的项目。运行时确定 ThreadPool 中有多少线程可用。
    • 实际上,看起来 TPL 确实在内部使用了 ThreadPool,所以我认为 Parallel.For 在性能方面与 QueueUserWorkItem 没有任何不同。见social.msdn.microsoft.com/Forums/eu/csharpgeneral/thread/…
    • 有趣。我使用 ThreadPool 是因为我认为它没有创建大量线程?无论哪种方式,瓶颈都在于从单个磁盘并行读取文件。在这一点上,我只是想尽可能快地将文件加载到内存中,由于我缺乏关于磁盘 I/O 的知识,我错误地认为多线程会更快。出于某种原因,我一直认为 TPL 只是 .net4 的东西,所以我肯定会研究我正在做的其他线程。
    【解决方案2】:

    当您需要决定多线程还是单线程时,您需要进行基准测试,最好是在将运行您的应用程序的机器上。

    由于线程同步的额外开销,多线程代码可能会更慢。即使你使用 ThreadPool,也会有线程创建的初始开销。

    如果不知道要解决的问题的细节,很难建议单线程或多线程哪个更好。

    此外,如果不查看代码,很难判断为什么一个代码比另一个慢。

    【讨论】:

      【解决方案3】:

      如果没有看到代码,我猜这可能与从磁盘读取是操作的缓慢部分这一事实有关。由于磁盘实际上一次只能读取一个文件,因此磁盘成为瓶颈。

      【讨论】:

      • 我更新了代码,我想在这种情况下使用线程没有真正意义,因为我一次只能从磁盘读取一个文件?
      • 我会说这是一种可能性。您可以通过将所有文件预加载到内存中进行测试,然后将它们加载到单线程与线程池中。这将使从磁盘中读取的内容排除在等式之外。当然,也可以是其他东西。正如其他答案所述,如果您只有 1 个处理器,多线程将无济于事。
      • 如果您考虑并行化解析可能是有意义的,但当然这可以缓解并行读取在您的 IO 系统上可能很困难。收益可能微不足道。 @rsbarro,可以使用 1 个 IO 线程对缓冲区和并行解析器进行排队。
      • @rsbarro,我试过了,线程池花费了几乎两倍的时间。我有一个 4 核的 i5。我正在加载 11,534 个文件,每个文件大约 10kb。
      • @dvhh 在我的评论中,我试图想出一种方法来确定磁盘是否是瓶颈,但是是的,我认为这将是一个好方法,使用单个 IO 线程。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-08
      • 2013-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-22
      • 1970-01-01
      相关资源
      最近更新 更多