通过并发增加磁盘读取吞吐量

时间:2017-09-08 08:21:49

标签: java concurrency java.util.concurrent

我正在尝试读取日志文件并解析它只消耗CPU。我有一个服务器读取230MB /秒的巨大文本文件,只读取文本文件不解析。当我尝试解析文本文件时,使用单线程,我可以解析文件大约50-70MB /秒。

我想提高吞吐量,实现并发工作。在此代码中,我达到130 MB /秒。在高峰期,我看到190MB /秒。我尝试过BlockedQueue,Semaphore,ExecutionService等。你有什么建议让我达到200MB /秒的吞吐量。

import { Router } from  '@angular/router';
    import { FormBuilder, FormGroup, Validators} from '@angular/forms';
    import { Location } from '@angular/common';
    constructor(public location: Location,public fb:FormBuilder,public global_service:GlobalService,public router: Router) { 

      }

3 个答案:

答案 0 :(得分:1)

您可能会受益于Java 8中引入的Files.lines()方法和Stream范例。它将使用系统公共fork / join池。试试这个模式:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class LineCounter
{
    public static void main(String[] args) throws IOException
    {
        Files.lines(Paths.get("/your/file/here"))
             .parallel()
             .forEach(LineCounter::processLine);
    }

    private static void processLine(String line) {
        // do the processing
    }
}

答案 1 :(得分:0)

假设你不在乎线的顺序:

    final String MARKER = new String(""); 
    BlockingQueue<String> q = new LinkedBlockingDeque<>(1024);
    for (int i = 0; i < concurrency; i++)
        executorService.execute(() -> {
            for (;;) {
                try {
                    String s = q.take();
                    if(s == MARKER) {
                        q.put(s);
                        return;
                    }
                    reader.splitNginxLinewithIntern(s);
                } catch (InterruptedException e) {
                    return;
                }
            }
        });
    String line;
    while ((line = reader.readLine()) != null) {
        q.put(line);
    }
    q.put(MARKER);
    executorService.awaitTermination(10, TimeUnit.MINUTES);

这会启动许多线程,每个线程都运行一个特定的任务;该任务是从队列中读取并运行split方法。读者只需输入队列,通知它何时完成并等待终止。

如果您要使用RxJava2和rxjava2-extras,那只是

    Strings.from(reader)
           .flatMap(str -> Flowable
              .just(str)
              .observeOn(Schedulers.computation())
              .doOnNext(reader::splitNginxLinewithIntern)
           )
           .blockingSubscribe();

答案 2 :(得分:0)

你需要多线程,你需要让读者线程将解析委托给工作线程,这是明确的。关键是如何以尽可能少的开销进行委托。

@Tassos提供的代码看起来像是一个可靠的改进。

您可以尝试的另一件事是更改委派粒度,而不是单独委派每一行,而是构建例如100行,从而将委派/同步开销减少了100倍(但后来需要一个String []数组或类似的,这不应该太大)。