使用带有RandomAccessFile的多个线程有助于提高性能吗?

drR*_*lol 5 java concurrency performance file-io multithreading

我正在开发一个(database-ish)项目,其中数据存储在一个平面文件中.对于读/写,我正在使用该RandomAccessFile课程.我是否可以从多线程获得任何东西,并为每个线程提供一个实例RandomAccessFile,或者一个线程/实例是否同样快?读/写是否有任何区别,因为你可以创建只进行读取的实例,而不能写?

RED*_*AIR 13

我现在用下面的代码做了一个基准测试(对不起,它在cpp中).该代码读取一个5 MB的文本文件,其中包含许多作为命令行参数传递的线程.

结果清楚地表明多线程总是加速程序:

更新:我想到,文件缓存将在这里发挥重要作用.所以我制作了testdata文件的副本,重新启动并为每次运行使用了不同的文件.下面更新了结果(括号中的旧结果).结论保持不变.

运行时间为秒

机器A(运行XP x64的双四核XEON,在RAID 5中具有4个10k SAS驱动器)

  • 1个主题:0.61s(0.61s)
  • 2个线程:0.44s(0.43s)
  • 4个线程:0.31s(0.28s)(最快)
  • 8个螺纹:0.53s(0.63s)

机器B(运行XP的双核笔记本电脑,带有一个支离破碎的2.5英寸驱动器)

  • 1线程:0.98s(1.01s)
  • 2个主题:0.67秒(0.61秒)(最快)
  • 4个主题:1.78s(0.63s)
  • 8个主题:2.06s(0.80s)

源代码(Windows):

// FileReadThreads.cpp : Defines the entry point for the console application.
//

#include "Windows.h"
#include "stdio.h"
#include "conio.h"
#include <sys\timeb.h>
#include <io.h>    

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int threadCount = 1;
char *fileName = 0;
int fileSize = 0;
double  GetSecs(void);

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

DWORD WINAPI FileReadThreadEntry(LPVOID lpThreadParameter)

{   char tx[255];

    int index = (int)lpThreadParameter;
    FILE *file = fopen(fileName, "rt");

    int start = (fileSize / threadCount) * index;
    int end   = (fileSize / threadCount) * (index + 1);

    fseek(file, start, SEEK_SET);

    printf("THREAD %4d started: Bytes %d-%d\n", GetCurrentThreadId(), start, end);


    for(int i = 0;; i++)
    {
        if(! fgets(tx, sizeof(tx), file))
            break;
        if(ftell(file) >= end)
            break;
    }
    fclose(file);

    printf("THREAD %4d done\n", GetCurrentThreadId());

    return 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////



int main(int argc, char* argv[])
{
    if(argc <= 1)
    {
        printf("Usage:  <InputFile> <threadCount>\n");
        exit(-1);
    }

    if(argc > 2)
        threadCount = atoi(argv[2]);

    fileName = argv[1];
    FILE *file = fopen(fileName, "rt");
    if(! file)
    {
        printf("Unable to open %s\n", argv[1]);
        exit(-1);
    }

    fseek(file, 0, SEEK_END);
    fileSize = ftell(file);
    fclose(file);


    printf("Starting to read file %s with %d threads\n", fileName, threadCount);
    ///////////////////////////////////////////////////////////////////////////
    // Start threads
    ///////////////////////////////////////////////////////////////////////////
    double start = GetSecs();

    HANDLE mWorkThread[255];        

    for(int i = 0; i < threadCount; i++)
    {
        mWorkThread[i] = CreateThread(
                  NULL,
                  0,
                  FileReadThreadEntry,
                  (LPVOID) i,
                  0, 
                  NULL);
    }
    WaitForMultipleObjects(threadCount, mWorkThread, TRUE, INFINITE);

    printf("Runtime %.2f Secs\nDone\n", (GetSecs() - start) / 1000.);
    return 0;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

double  GetSecs(void)

{
        struct timeb timebuffer;
        ftime(&timebuffer);
        return (double)timebuffer.millitm + 
              ((double)timebuffer.time * 1000.) - // Timezone needed for DbfGetToday
              ((double)timebuffer.timezone * 60. * 1000.);
}
Run Code Online (Sandbox Code Playgroud)


RED*_*AIR 9

根据我从C++开发的经验,答案是:是的,使用多个线程可以在读取文件时提高性能.这适用于顺序和串行访问.我不止一次地证明了这一点,尽管我总是发现真正的瓶颈在其他地方.

原因是,对于磁盘访问,线程将被挂起,直到磁盘操作完成.但是现在大多数磁盘都支持本机命令队列(SAS)Segate(SATA)(以及大多数RAID系统),因此不必按照您的顺序处理请求.

因此,如果您按顺序读取4个文件块,则您的程序必须等待第一个块,然后您请求第二个块,然后请求第一个块.如果您请求包含4个线程的4个块,则可以一次性返回它们.这种优化有限,但它有效(虽然我在这里只有C++的经验).我测量了多个线程可以将顺序读取性能提高100%以上.


Pet*_*rey 2

一个相当常见的问题。基本上使用多线程不会让你的硬盘运行得更快。相反,执行并发请求可能会使速度变慢。

磁盘子系统(尤其是 IDE、EIDE、SATA)设计为按顺序读取/写入速度最快。

  • 这不是真的。大多数磁盘支持本机命令队列。请参阅http://www.seagate.com/content/pdf/whitepaper/D2c%5Ftech%5Fpaper%5Fintc-stx%5Fsata%5Fncq.pdf (8认同)
  • @Peter:你是否认为这是针对你个人的,取决于你自己,但事实不会因为你的感受而改变。 (2认同)