簡體   English   中英

Java - 用三個線程處理文件

[英]Java - Processing file with three threads

ExecutorService executor1 = Executors.newSingleThreadExecutor();
        ExecutorService executor2 = Executors.newSingleThreadExecutor();
        ExecutorService executor3 = Executors.newSingleThreadExecutor();
        ArrayBlockingQueue<String> abq = new ArrayBlockingQueue<String>(1000);
        try {

             String line;
             InputStream is = file.getInputStream();
             br = new BufferedReader(new InputStreamReader(is));
             while ((line = br.readLine()) != null) {
                 String[] values = line.split(",");
                 List<String> valuesList = Arrays.asList(values);
                 for(String valueList : valuesList) {
                     abq.put(valueList);
                     executor2.execute(new Runnable () {
                         public void run() {
                             System.out.println(valueList + Thread.currentThread().getName());
                         }
                     });       

嗨,我正在嘗試執行以下操作:

  1. 從主線程讀取文件
  2. 將讀取值存儲到阻塞隊列,另一個線程將從中訪問和處理。
  3. 讓另一個線程寫入另一個文件。
    但我對如何做到這一點感到困惑。 如果我聲明了一個固定線程池,我將無法控制哪個線程做什么,但是在這種方法中,這與順序處理是否相似,因為線程屬於不同的池?
    如果有人可以指導我如何做到這一點,那將對我有很大幫助。

我不知道我是否理解你想要做什么,但我會這樣做:我創建了 3 個線程並以不同的方式命名它們,基於我讓它們運行 3 種不同方法的名稱:第一個讀取文件並將結果放入所有 trheads 和 static 共享的 arraylist 中,第二個有一個無限循環(或者如果你想進行一些優化,則每隔特定時間運行一個任務),它總是采用 arraylist 的第一個元素並處理它和將它放在另一個也是共享和靜態的數組列表中,第三個線程也有一個循環(或任務),它總是采用第一個元素並將其打印到文件中。

我會這樣做,但也許我不明白,如果你需要寫信給我

(谷歌翻譯從:意大利語到:英語)

我們正在執行以下兩項任務:

  1. 讀取 + 反序列化輸入(從文件中讀取字節並解析為 Java 對象“消息”)
  2. 序列化 + 寫入輸出(轉換為目標格式並寫入)

請注意,可能僅在查看某些特定的高吞吐量場景時才需要使用 2 個不同線程順序工作並同步(阻塞)消息切換的方法。 與每個線程的每個任務相關聯的工作通常必須平衡(即占用相似數量的 CPU 周期),這甚至是有益的。 或者,該輸出被寫入例如雲存儲或可能間歇性停止的東西。

您是正確的,您必須使用線程安全隊列在線程之間進行切換! 最簡單的方法是直接實例化和設置兩個線程之間的交互(而不是使用 ExecutorService)。

有關代碼示例,請參見下文。 這里我們假設表示消息的 Java 對象稱為MyMsg ,並且序列化形式在輸入和輸出文件中都是基於String的:

public class ProcessorExample {

  private static final MyMsg END = new MyMsg(); // used to signal file read finished

  public void processFile(File inFile, File outFile) {
    BlockingQueue<MyMsg> queue = new ArrayBlockingQueue<>(4096);
    Thread reader = new Thread(() -> read(queue, inFile), "reader");
    Thread writer = new Thread(() -> write(queue, outFile), "writer");
    reader.start();
    writer.start();
  }

  private void read(BlockingQueue<MyMsg> queue, File inFile) {
    try (BufferedReader reader = new BufferedReader(new FileReader(inFile))) {
      String line;
      while ((line = reader.readLine()) != null) {
        queue.put(deserialize(line)); //surround with try/catch to drop failed messages
      }
      queue.put(END);
    } catch (IOException|InterruptedException e) {
        // TODO: Graceful handling of exceptions at file level
    }
  }

  private void write(BlockingQueue<MyMsg> queue, File outFile) {
    try (BufferedWriter writer = new BufferedWriter(new FileWriter(outFile))) {
      MyMsg msg;
      while ((msg = queue.take()) != END) {
        writer.write(serialize(msg)); //surround with try/catch to drop failed messages
      }
    } catch (IOException|InterruptedException e) {
      // TODO: Graceful handling of exceptions at file level
    }
  }

  private MyMsg deserialize(String str) {
    return null; //TODO implement
  }

  private String serialize(MyMsg msg) {
    return null; //TODO implement
  }

}

最后的一些想法:

  • 為了獲得最高吞吐量,請考慮使用JCTools 中的無鎖單生產者單消費者隊列而不是ArrayBlockingQueue
  • 盡可能在實際工作負載上測試您的代碼,以獲得適用於您的用例的真實性能數據。
  • 如果您要處理大量文件 (>10k),最好開始重用線程。
  • 如果這實際上不是“高吞吐量”場景,而是反序列化/序列化緩慢的問題,那么我建議首先看看如何改進這些方法。 那里有很棒的算法和庫來執行可能需要很長時間的東西(讀取巨大的 XML 等)

我看到發布了各種解決方案,但我懷疑您是否想將讀取和寫入完全分開。

如果您要並行處理許多文件,那么我將從順序讀取和寫入單個線程開始,這樣就不需要同步,因此您不會浪費 CPU 的潛力。

您可以通過多個線程並行處理多個文件。

我將首先創建一些基准測試,例如使用 JMH,然后在跳入多線程解決方案之前查看實際瓶頸是什么。 如果使用得當,單個 CPU 可以完成大量工作。

如果您使用的是 Linux,那么對於簡單的順序 I/O,您不需要等待磁盤訪問(因此它不是同步的)。 Linux 使用了一種稱為預讀的功能,它會將您的進程將要讀取的數據預取到頁面緩存中。 因此,當您的本地讀取緩沖區耗盡時,它只需要查看頁面緩存以在用戶空間緩沖區中加載下一個數據,因為預讀可能已經將數據加載到頁面緩存中。 對於緩沖 I/O,寫入也首先在用戶空間緩沖區中結束; 一旦緩沖區填滿,它就會被寫入頁面緩存。 只有在未來的某個時刻,臟頁才會寫入磁盤。 現代 NVMe SSD 的順序讀/寫速度非常快(每秒數 GB)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM