【问题标题】:How many filereaders can concurrently read from the same file?有多少个文件读取器可以同时从同一个文件中读取?
【发布时间】:2014-05-30 22:36:59
【问题描述】:

我有一个 25GB 的 CSV 文件。我知道文件中有大约 5 亿条记录。

我想对数据进行一些基本分析。没什么太花哨的。

我不想使用 Hadoop/Pig,至少现在还不想。

我编写了一个 java 程序来同时进行分析。这就是我正在做的事情。

class MainClass {
 public static void main(String[] args) {
  long start = 1;
  long increment = 10000000;
  OpenFileAndDoStuff a = new OpenFileAndDoStuff[50];
  for(int i=0;i<50;i++) {
    a[i] = new OpenFileAndDoStuff("path/to/50GB/file.csv",start,start+increment-1);
    a[i].start();
    start += increment;
  } 
  for(OpenFileAndDoStuff obj : a) {
     obj.join();
  }
  //do aggregation 
 }
}

class OpenFileAndDoStuff extends Thread {
  volatile HashMap<Integer, Integer> stuff = new HashMap<>();
  BufferedReader _br;
  long _end;
  OpenFileAndDoStuff(String filename, long startline, long endline) throws IOException, FileNotFoundException {
    _br = new BufferedReader(new FileReader(filename));
    long counter=0;
    //move the bufferedReader pointer to the startline specified
    while(counter++ < start) 
     _br.readLine();
    this._end = end;
  }
  void doStuff() {
    //read from buffered reader until end of file or until the specified endline is reached and do stuff
  }
  public void run() {
    doStuff();
  }
  public HashMap<Integer, Integer> getStuff() {
    return stuff;
  } 
}

我想这样做我可以打开 50 个缓冲读取器,所有这些都并行读取 1000 万行卡盘,一旦它们都完成了它们的工作,我就会聚合它们。

但是,我面临的问题是,即使我要求启动 50 个线程,但一次只有两个启动,并且一次可以从文件中读取。

有没有办法让所有 50 个文件同时打开并读取文件?为什么我一次只能阅读两个读者?

该文件位于 Windows 8 机器上,而 java 也在同一台机器上。

有什么想法吗?

【问题讨论】:

  • @etherous 我已经在尝试并这样做了,但是我不能同时从文件中读取两个以上的 bufferedReader。请参阅有关我如何操作的说明。你的评论就像有人告诉我宇宙中某处存在一块完美的圆形石头一样含糊。
  • 在这种情况下,如果不使用 NIO,您只会走这么远。我会使用 FileChannel。你想要一个例子吗?编辑:docs.oracle.com/javase/tutorial/essential/io/rafs.html
  • @etherous 当然。我现在正在 oracle 文档上查找它,但是一个例子会很棒。但是,这正是我想要的。感谢您指出正确的方向!
  • 我提供的链接与您可能想要的非常接近。您需要做的唯一修改是创建多个实例并为每个实例分区文件
  • 看来这个文件有效地作为一个链表工作。因此,您告诉要处理 400 万至 500 万行的线程也必须实际读取前 400 万行。我不相信您将能够实现高水平的并发性,除非您可以对文件进行“索引”访问。然后,您可以使用 FileChannel 或 RandomAccessFile 打开文件,并专门跳转到该线程应该处理的文件部分。

标签: java file-io


【解决方案1】:

我看到的一个问题是,当要求线程读取例如第 80000000 到 90000000 行时,您仍在读取前 80000000 行(并忽略它们)。

也许可以试试java.io.RandomAccessFile

为此,您需要所有行的字节数相同。如果您无法调整文件的结构,那么这不是一个选择。但如果可以的话,这应该允许更大的并发性。

【讨论】:

    【解决方案2】:

    这是一个类似的帖子:Concurrent reading of a File (java preffered)

    这里最重要的问题是瓶颈是什么在你的情况下?

    如果瓶颈是您的磁盘 IO,那么您在软件部分无能为力。并行计算只会让事情变得更糟,因为同时从不同部分读取文件会降低磁盘性能。

    如果瓶颈是处理能力,并且您有多个 CPU 内核,那么您可以利用启动多个线程来处理文件的不同部分。您可以安全地创建多个 InputStreams 或 Readers 来并行读取文件的不同部分(只要您不超过操作系统对打开文件数量的限制)。您可以将工作分成任务并并行运行

    有关使用 FileInputStream 并行读取单个文件的示例,请参阅参考文章,根据这些基准,这应该比使用 BufferedReader 快得多:http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly#FileReaderandBufferedReader

    【讨论】:

      猜你喜欢
      • 2015-01-05
      • 1970-01-01
      • 2012-07-18
      • 2018-01-20
      • 2011-04-01
      • 1970-01-01
      • 2010-10-23
      • 2019-10-17
      相关资源
      最近更新 更多