使用多线程读取单个文件:应该加快速度吗?

Posted

技术标签:

【中文标题】使用多线程读取单个文件:应该加快速度吗?【英文标题】:Reading a single file with Multiple Thread: should speed up? 【发布时间】:2012-01-10 20:14:28 【问题描述】:

我正在读取一个包含 500000 行的文件。 我正在测试看多线程如何加快进程....

private void multiThreadRead(int num)

    for(int i=1; i<= num; i++)  
        new Thread(readIndivColumn(i),""+i).start(); 
      


private Runnable readIndivColumn(final int colNum)
    return new Runnable()
        @Override
        public void run() 
            // TODO Auto-generated method stub
            try 

                long startTime = System.currentTimeMillis();
                System.out.println("From Thread no:"+colNum+" Start time:"+startTime);

                RandomAccessFile raf = new RandomAccessFile("./src/test/test1.csv","r");
                String line = "";
                //System.out.println("From Thread no:"+colNum);

                while((line = raf.readLine()) != null)
                    //System.out.println(line);
                    //System.out.println(StatUtils.getCellValue(line, colNum));
                


                long elapsedTime = System.currentTimeMillis() - startTime;

                String formattedTime = String.format("%d min, %d sec",  
                        TimeUnit.MILLISECONDS.toMinutes(elapsedTime), 
                        TimeUnit.MILLISECONDS.toSeconds(elapsedTime) -  
                        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(elapsedTime)) 
                    );

                System.out.println("From Thread no:"+colNum+" Finished Time:"+formattedTime);
             
            catch (Exception e) 
                // TODO Auto-generated catch block
                System.out.println("From Thread no:"+colNum +"===>"+e.getMessage());

                e.printStackTrace();
            
        
    ;


private void sequentialRead(int num)
    try
        long startTime = System.currentTimeMillis();
        System.out.println("Start time:"+startTime);

        for(int i =0; i < num; i++)
            RandomAccessFile raf = new RandomAccessFile("./src/test/test1.csv","r");
            String line = "";

            while((line = raf.readLine()) != null)
                //System.out.println(line);
                           
        

        long elapsedTime = System.currentTimeMillis() - startTime;

        String formattedTime = String.format("%d min, %d sec",  
                TimeUnit.MILLISECONDS.toMinutes(elapsedTime), 
                TimeUnit.MILLISECONDS.toSeconds(elapsedTime) -  
                TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(elapsedTime)) 
            );

        System.out.println("Finished Time:"+formattedTime);
    
    catch (Exception e) 
        e.printStackTrace();
        // TODO: handle exception
    


    public TesterClass() 

    sequentialRead(1);      
    this.multiThreadRead(1);


对于 num = 1,我得到以下结果:

开始时间:1326224619049

完成时间:2 分 14 秒

顺序读取ENDS............

多线程读取开始:

从线程号:1 开始时间:1326224753606

从线程号:1 完成时间:2 分 13 秒

多线程读取结束.....

对于 num = 5,我得到以下结果:

    formatted Time:10 min, 20 sec

Sequential read ENDS...........

Multi-Thread read starts:

From Thread no:1 Start time:1326223509574
From Thread no:3 Start time:1326223509574
From Thread no:4 Start time:1326223509574
From Thread no:5 Start time:1326223509574
From Thread no:2 Start time:1326223509574
From Thread no:4 formatted Time:5 min, 54 sec
From Thread no:2 formatted Time:6 min, 0 sec
From Thread no:3 formatted Time:6 min, 7 sec
From Thread no:5 formatted Time:6 min, 23 sec
From Thread no:1 formatted Time:6 min, 23 sec
Multi-Thread read ENDS.....

我的问题是:不应该多线程读取大约需要。 2.13 秒? 您能否解释一下为什么使用多线程解决方案需要很长时间?

提前致谢。

【问题讨论】:

Java multi-thread application that reads a single file的可能重复 线程将无法工作,除非它们写入不同的磁盘,在这种情况下,两个线程都在竞争写入同一个文件。因此,线程在这种情况下将不起作用。 @TomaszNurkiewicz - 不一样,每个文件使用一个线程。 【参考方案1】:

您看到并行读取速度变慢的原因是磁性硬盘磁头需要为每个线程寻找下一个读取位置(大约需要 5 毫秒)。因此,使用多线程读取会在两次查找之间有效地反弹磁盘,从而减慢它的速度。从单个磁盘读取文件的唯一推荐方法是使用一个线程顺序读取。

【讨论】:

感谢您的 cmets。即使多线程读取需要更多时间(例如 6.2 分钟而不是 2.10 分钟),我仍然可以节省 4/5 分钟,而我通过顺序读取迭代 5 次(即顺序读取 = 10.20 分钟;其中 5线程 = 6.20 分钟)【参考方案2】:

由于文件读取主要是等待磁盘 I/O,因此您会遇到磁盘不会因为被许多线程使用而旋转得更快的问题:)

【讨论】:

I/O 锁定策略可能取决于 java 实现和底层操作系统。 我正在为同一个用例执行测试 - 从多个线程读取单个文件。我发现如果底层存储是 SATA 磁盘驱动器,则拥有多个线程可以提高性能,而如果它是 SAS 驱动器,则可以提高性能。是因为点对点技术还是我的测试做错了什么?【参考方案3】:

从文件读取本质上是一个串行过程,假设没有缓存,这意味着从文件中检索数据的速度是有限的。即使没有文件锁(即以只读方式打开文件),第一个之后的所有线程也只会阻塞磁盘读取,因此您让所有其他线程等待,并且当数据可用时,无论哪个线程处于活动状态都是处理下一个区块。

【讨论】:

以上是关于使用多线程读取单个文件:应该加快速度吗?的主要内容,如果未能解决你的问题,请参考以下文章

加快读取多个泡菜文件

JAVA多线程到底能不能加快程序运行速度?

Java多线程并发操作数据库能否提高运行速度。

在 Python 脚本中同时使用多处理和多线程来加快执行速度

多线程可以加速内存分配吗?

c# 为啥读取Txt文件太慢?