【问题标题】:Writing a file using multiple threads使用多个线程写入文件
【发布时间】:2015-11-26 19:53:49
【问题描述】:

我正在尝试使用多个线程在 Java 中编写一个大文件。

我已经尝试过 Java 中的 FileWriterbufferedWriter 类。

正在写入的内容实际上是使用CopyManager 读取和写入的整个表(Postgres)。文件中的每一行都是表中的一个元组,我一次要写 100 行。

写法:

单个待写文件被多个线程以追加方式打开。 此后每个线程都尝试写入文件file。

以下是我面临的问题:

  • 文件的内容有时会被覆盖,即:一行仍然不完整,下一行从那里开始。我的假设是 writer 的缓冲区已满。这迫使写入者立即将数据写入文件。写入的数据可能不是完整的一行,在它可以写入其余部分之前,下一个线程将其内容写入文件。
  • 在使用 Filewriter 时,我偶尔会在文件中看到一条黑线。

有什么建议,如何避免这个数据完整性问题?

【问题讨论】:

标签: java multithreading postgresql file-io bufferedwriter


【解决方案1】:

与其拥有同步方法,更好的解决方案是拥有一个由阻塞队列支持的单线程线程池。将要写入的消息应用程序将被推送到阻塞队列。日志写入线程将继续从阻塞队列中读取(如果队列为空,将被阻塞)并将继续将其写入单个文件。

【讨论】:

    【解决方案2】:

    共享资源 == 争用

    根据定义写入普通文件是一个序列化操作。尝试从多个线程写入它不会获得任何性能,I/O 是一种有限的有界资源,其带宽甚至比最慢或最过载的 CPU 还要少几个数量级。

    对共享资源的并发访问可能很复杂(而且速度很慢)

    如果您有多个线程正在执行昂贵的计算,那么您可以选择,如果您只是使用多个线程,因为您认为您会加快某些事情的速度,那么您只会做相反的事情。 I/O 争用总是会减慢对资源的访问速度,但由于锁等待和其他开销,它永远不会加快速度。

    您必须有一个受保护的关键部分,并且一次只允许一个写入者。只需查找任何支持并发的日志编写器的源代码,您就会发现只有一个线程写入文件。

    如果您的应用主要是:

    1. CPU Bound:您可以使用一些锁定机制/数据结构来一次只让多个线程中的一个线程写入文件,从并发的角度来看,这作为一种幼稚的解决方案是没有用的;如果这些线程受 CPU 限制且 I/O 很少,这可能会起作用。

    2. I/O Bound: 这是最常见的情况,您必须使用带有某种队列的消息传递系统,并让所有线程发布到队列/缓冲区,并且只有一个线程从中拉出并写入文件。这将是最具可扩展性和最容易实施的解决方案。

    日志 - 异步写入

    如果您需要创建单个超大文件,其中写入顺序不重要且程序受 CPU 限制,您可以使用日志技术。

    让每个process 写入一个单独的文件,然后在最后将多个文件连接成一个大文件。这是一个非常老派的低技术解决方案,效果很好,并且已经使用了几十年。

    显然,您拥有的存储 I/O 越多,这将在最后连接时执行得越好。

    【讨论】:

      【解决方案3】:

      我正在尝试使用多个线程在 Java 中编写一个大文件。

      我建议您使用 X 个线程从数据库中读取数据,并让一个线程写入您的输出文件。与执行文件锁定等相比,这将更容易实现。

      您可以使用共享的BlockingQueue(可能是ArrayBlockingQueue),这样数据库读取器将add(...) 加入队列,而您的写入器将在队列中的take() 循环中。当阅读器完成后,他们可以添加一些特殊的IM_DONE 字符串常量,一旦写入线程看到这些常量中的 X 个(即每个阅读器一个),它就会关闭输出文件并退出。

      那么你可以使用单个BufferedWriter 而不需要任何锁等。您可能会被数据库调用而不是本地 IO 阻塞。当然,额外的线程根本不会减慢您的速度。

      单个待写文件被多个线程以追加方式打开。此后每个线程都尝试写入文件file。

      如果您坚持让您的阅读线程也进行写入,那么您应该在对单个共享BufferedWriter 的访问周围添加一个synchronized 块——您可以在BufferedWriter 对象本身上进行同步。知道何时关闭 writer 有点问题,因为每个线程都必须知道另一个线程是否已经退出。每个线程可以在运行时增加共享的AtomicInteger,并在完成时减少。然后查看运行计数并看到 0 的线程将关闭编写器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多