【问题标题】:Multithread file reading overhead in javajava中的多线程文件读取开销
【发布时间】:2014-04-15 13:04:45
【问题描述】:

我的服务器在处理器、存储吞吐量和内存方面拥有大量资源,可用于处理大量文件。

我正在做一些性能测试,并调整了一个小型java程序来测试并行读取。代码如下

import java.io.*;
import java.lang.*;
class MultiThreadedFileRead extends Thread
{
        InputStream in;
        MultiThreadedFileRead(String fname) throws Exception
        {
                in=new FileInputStream(fname);
                this.start();
        }
        public void run()
        {
                int i=0;
                while(i!=-1)
                {
                        try
                        {
                            i=in.read();
                            //System.out.print((char)i);
                                                        continue;
                        }catch(Exception e){}
                }
                try
                {
                        in.close();
                }catch(Exception e){}
        }
        public static void main(String a[]) throws Exception
        {
                int n=[0];
                MultiThreadedFileRead fr[]=new MultiThreadedFileRead[n];
                long tim;
                tim=System.currentTimeMillis();
                for(int i=1;i<n;i++)
                        fr[i]=new MultiThreadedFileRead(a[i]);
                for(int i=1;i<n;i++)
                {
                        try
                        {
                                fr[i].join();
                        }catch(Exception e){}
                }
                System.out.println("Time Required : "+(System.currentTimeMillis()-tim)+" miliseconds.");
        }
}

结果似乎是正确的:并行读取 10 个文件(10 个线程)所花费的时间与读取一个文件/一个线程所花费的时间大致相同,而且还需要一些开销。 (对不起,我这里没有实际数字,以后可能会编辑添加它)

但可以肯定的是,我想知道打开线程以进行并行读取的预期或“合理”开销是多少...?

另外,我不是一个java开发者,所以虽然程序很简单,但如果我有什么不对的地方请指出。

ps。要运行程序,我有 10x10mb 文件(名为 tf0、tf1、tf2 等),我以 java MultiThreadedFileRead 10 tf* 运行测试(用于 10 个线程)。

【问题讨论】:

    标签: java multithreading io


    【解决方案1】:

    研究启动线程所需的时间毫无意义,主要有两个原因:

    1. 与读取文件所需的时间相比,这将是微不足道的 - 除非您拥有一些经过严格授权的系统。
    2. 您收集的统计信息将特定于您正在测试的系统 - 将其移至另一个系统,在炎热/寒冷的日子运行它,您的统计信息将毫无意义。

    如果您正在寻找真正的性能提升,您最好研究在多台机器上实际分布进程。

    【讨论】:

    • 酷,我同意,只是在检查。现在,mrVoid 的答案呢?即使他说 IO 不是多线程的,我的程序似乎也能按预期运行......
    • @filippo - 可能有大量的缓冲和预读缓存正在进行,以确保您看到似乎是线性缩放的。如果您更改为随机查找/读取/写入,您可能会开始遭受磁盘 I/O 线性度的影响,但同样 - 这取决于您的硬件。如果您正在使用 SSD 或 NAS,您的时间将再次不同。过早的优化是错误的。
    【解决方案2】:

    我认为问题可能在于IO 本身不是多线程的

    如果您创建 X 个线程并且它们都在 IO 上发出读取,则它不会快 X 倍,因为它执行 IO 读取顺序。

    我已经测试了 9 个线程和 1 个线程文件(每个 100MB)的代码。结果是 208 秒和 94 秒。

    在我看来,测试存在两个问题:

    1. 无缓冲读取(逐字节)无法获得最大吞吐量。
    2. 您正在测试中创建 n-1 个线程。

    【讨论】:

    • OP 没有问题。在 10 个线程中读取 10 个文件所需的时间与在 1 个线程中读取 1 个文件一样长(加上一点开销)。所以使用 10 个线程的加速是 10 倍。他的问题是关于这个小开销。
    • 我运行的测试似乎证实了我的答案。
    • @mrVoid 我明白了。至于 n-1,它是我在此处发布的一个小编辑的错误。至于性能,这并不是重点——我只是想要一个可重复的测试。不过,我会按照 Michael 的建议将脚本放入 NIO!非常感谢!
    【解决方案3】:

    如果这是服务器,您可能应该使用线程池而不是重新创建线程。这将消除线程创建开销(单次除外),并防止您的服务器在请求过多时停机。

    http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html

    此外,您可能需要考虑非阻塞 io,以获得真正的性能提升。

    http://tutorials.jenkov.com/java-nio/nio-vs-io.html

    当使用正常读取时,正如@mrVoid 建议的那样,您应该使用缓冲读取器。

    你可能想加入一些缓存机制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-28
      • 2019-06-02
      • 2017-11-27
      • 1970-01-01
      相关资源
      最近更新 更多