【问题标题】:Why multithreading is slower on file writing in java为什么多线程在java中写入文件时速度较慢
【发布时间】:2018-12-22 10:40:30
【问题描述】:

我是多线程新手,今天我尝试在相同条件下运行一些多线程与单线程程序的性能测试。令我惊讶的是,我发现单线程选项的工作速度比多线程选项要快一些。那么可能是什么原因呢?

我编写了一个带有字符串连接类的简单程序,它将结果写入文件。我创建了 5 个包含 50000 个零的数组和 5 个输出文件,它们在 for 循环中传递给 Appender 类的构造函数。在多线程选项中,我调用 appender.run(),在单线程选项中,我注释掉所有与线程相关的行并改为调用 appender.appendString();

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class Main {

    public static void main(String[] args) throws InterruptedException {
        int[][] input = {new int[50000], new int[50000], new int[50000], new int[50000], new int[50000]};

        File[] outputFiles = {new File("src\\text6.txt"), new File("src\\text7.txt"), new File("src\\text8.txt"),
                new File("src\\text9.txt"), new File("src\\text10.txt")};

        long startTime = System.currentTimeMillis();
        Thread[] threads = new Thread[5];
        for (int i = 0; i < 5; i++) {
            Appender appender = new Appender(input[i], outputFiles[i]);
            threads[i] = new Thread(appender);
            threads[i].start();
            appender.run();
        }

        for (Thread thread : threads) {
            thread.join();
        }
        long stopTime = System.currentTimeMillis();

        System.out.println(stopTime - startTime);
    }
}

class Appender implements Runnable {

    private String result;
    private int[] input;
    private File outputFile;

    public Appender(int[] input, File outputFile) {
        this.result = "";
        this.input = input;
        this.outputFile = outputFile;
    }

    public void appendString() {
        for (int number : input) {
            this.result += String.valueOf(number);
        }

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(this.outputFile));) {
            writer.write(this.result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        appendString();
    }
}

测量的执行时间(以毫秒为单位)适用于多线程大约 3600-3700 和单线程 2800-2900。与我的预期完全相反,因为所有线程都在不同的数组上工作并写入不同的文件。

【问题讨论】:

  • 这将是 I/O 主导的,不是吗?对于旋转媒体,您可能会得到更差的结果(我假设您使用的是 SSD)。
  • 你的系统有多少个内核?
  • 这可能是您的代码示例中的拼写错误,或者是我对您评论的内容的误解而没有注释掉。但是在您调用“appender.run();”的“多线程”示例中,您应该只调用 Thread start(线程将为您调用 appender 上的 .run())。请参阅此处的其他答案以获取更多信息,但这可能有助于使您的示例更清晰
  • 在我的机器上,单线程变体运行 6100 毫秒,多线程变体运行 5700 毫秒,因此顺序与您观察到的完全相反,而它们都是无论如何,运行速度比你的配置慢两倍。
  • “所有线程......写入不同的文件” - 但这些文件是否在不同的设备上,这是个问题。

标签: java multithreading performance


【解决方案1】:

简短的回答是,多线程本身并不能加速一切。事实上,它可以减慢一些事情;我没有分析您的代码,但您可能已经在示例中向自己展示了这一点。

为了让单处理器计算机进行多线程处理,它在时间“切片”中工作;它在一个切片上工作一段时间,然后在另一个切片上工作一段时间,等等。即使在单处理器机器上,这在桌面 UI 等情况下也有很大的优势,您希望鼠标光标和键盘按钮在程序同时做其他事情的同时继续为用户响应。

但是如果你的程序是“计算密集型”的,也就是说,如果程序速度的限制因素是处理器可以执行的速度,那么多线程不会有任何好处关于单处理器示例。两个线程不能同时执行,因此在代码中使用多线程所做的只是增加了维护有关时间片的信息和在时间片之间切换的开销。

当代码花费一些时间等待 I/O 时,多线程也有很大的好处。一个线程可以获取输入,将该输入交给另一个线程进行处理,然后在循环中返回以获取更多输入。如果在单处理器机器上没有多线程,等待 I/O 所花费的时间不允许任何处理完成,而多线程将允许计算继续进行。

在多处理器机器上会变得不同(而且更复杂);您没有提到您在处理器方面的情况,但我希望这足以让您开始了解正在发生的事情。

【讨论】:

    【解决方案2】:

    感谢大家的回答!我从他们身上学到了很多!我的代码中的问题是一行不应该存在的代码。 goughy000 让我大开眼界,我不应该调用 appender.run() 方法,因为 thread.start() 调用了它。现在多线程时间下降到 1800-1900 毫秒。

    【讨论】:

      【解决方案3】:

      您的代码不进行计算,它只是将静态数据复制到文件中。您肯定是受磁盘 I/O 限制,而不是受 CPU 限制。

      同时写入多个文件是一种悲观;顺序模式下磁盘 I/O 速度最快(在 HDD 上最大限度地减少磁头移动,在 SSD 上写入大块比写入小块更快)。

      一旦计算数据比存储数据慢,那么您将受益于并行化计算部分(而不是存储部分)。

      【讨论】:

        【解决方案4】:

        根据 Oracle 的 The Java™ Tutorials on processes and threads here 它提到:

        线程共享进程的资源,包括内存和打开 文件。这使得高效,但潜在的问题, 交流。

        正如 arcy 在他的回答中提到的,有很多因素会影响多线程环境的执行。

        【讨论】:

          猜你喜欢
          • 2019-03-02
          • 2013-07-23
          • 2016-02-06
          • 2014-03-07
          • 2023-04-02
          • 1970-01-01
          • 2017-07-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多