【问题标题】:Waiting for ThreadPool to finish等待线程池完成
【发布时间】:2015-08-29 09:33:28
【问题描述】:

我开发了一个应用程序,将 10000 行 lorem ipsum 保存在磁盘上的 .txt 文件中。我使用 StreamWriter 来实际编写这些行,并使用 ThreadPool 将计算过程分配给可用的线程/内核。

保存速度非常快,即使有 100 万行,但问题是,并非所有行都被保存,最后一行被部分保存。当我关闭程序时,由于某种原因它再次写入文件。

我有以下字符串:

String loremipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

剩下的代码是:

    private StreamWriter writer = new StreamWriter("loremipsum.txt");
    private Object lockObject = new Object();

    // Button that initiates the process
    private void btnSave_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 1; i <= 10000; i++)
        {
            ThreadPool.QueueUserWorkItem(state =>
            {
                SaveFile(writer, loremipsum);
            });
        }
    }

    private void SaveFile(StreamWriter w, String text)
    {
        lock (lockObject)
        {
            w.WriteLine(text);
        }
    }

由于 StreamWriter 不是线程安全的,我使用的是锁定对象。

如果我在运行程序的情况下打开 .txt 文件,它只有 9998 行,最后一行不完整。

如果我关闭程序,它会再次重写文件,添加所有行,但最后一行仍然不完整。为什么会这样?

我想这些行被部分保存了,因为 ThreadPool 的线程需要一些时间来完成它们的工作。我对么?如果是这样,我该如何实现?

【问题讨论】:

  • 你是否使用了 Flush() 然后 Close()。像所有流类一样,streamwriter 缓冲写入数据,并且直到缓冲区已满才真正写入文件。通常对于流,最后一个缓冲区不会被写入,使用 Flush() 可以解决问题。
  • 没有任何理由可以为此使用多个线程。这里没有 CPU 绑定操作,一次只能写一行。只需将所有 10,000 行写在一个线程中,完成后不要忘记处理 StreamWriter
  • @CharlesMager 我不知道,但是使用 ThreadPool 执行此操作会导致操作非常快,我尝试仅使用一个线程编写,但它需要 10 倍的时间。
  • 那么它可能没有按照您的想法进行。由于您的锁定,所有内容都必须同步,因此即使使用多个线程,一次也只能写入一行。加上开销。这应该更慢(也是一个坏主意)。
  • 完成后如何检查?您的事件处理程序几乎会立即返回,但您不知道所有任务何时执行完毕。

标签: c# multithreading threadpool streamwriter


【解决方案1】:

线程池正在让后台线程执行如果主线程中止将停止的任务。您必须等待所有线程完成,然后刷新流。 由于您只缺少最后几行,因此您更有可能在那里只有一个 Flush() 问题,而不是中止的线程。

我相信您也知道您的代码比在单个线程中完成工作更糟糕。在创建所有开销时,那里没有真正的并行性发生。

【讨论】:

  • 我应该把它冲进锁里吗?
  • 可以,但效率不高。理想情况下,您在完成一批写作后进行冲洗。 flush 将强制执行磁盘访问,这是一项昂贵的操作。在那里执行 10000 次刷新
  • 好的,我可以使用 ManualResetEvent 等待线程完成然后刷新并关闭 StreamWriter 吗?
  • 可能,但由于您可以创建的 MRE 数量的限制,您可能会遇到另一个错误。是稀缺的操作系统资源。如果目标是实现线程安全的流编写器,我会回到绘图板上。例如,如何在生产者/消费者模式中拥有一个线程写入的缓冲区,并且只有一个线程正在写入然后刷新。
猜你喜欢
  • 2010-10-16
  • 1970-01-01
  • 2014-03-18
  • 2011-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多