将几个ByteArrayOutputStream合并到一个FileOutputStream中

时间:2013-05-16 03:17:52

标签: java multithreading concurrency io

我在八个线程中拆分计算并将结果写入文件,如下所示:

1a上。七个线程中的每一个都处理其输入并将其输出写入其自己的ByteArrayOutputStream;当流关闭时,线程offers<Integer, ByteArrayOutputStream>ConcurrentLinkedQueue,并在countDown()上调用CountDownLatch(已初始化为7)。

1b中。同时,第八个线程读入将在下一次迭代中处理的所有输入数据。当awaits完成对其数据的读取时,此帖子CountDownLatch

2a上。当CountDownLatch达到0时,第八个线程唤醒,使用ConcurrentinkedQueue中的Integer作为排序键对<Integer, ByteArrayOutputStream>进行排序,然后遍历队列并附加字节数组到文件。 (可能有一种更有效的方式来按顺序遍历列表而不对其进行排序,但列表中只有七个元素,因此排序方法的运行时不是问题。)

2B。同时,其他七个线程处理由第八个线程为它们准备的输入。

**此过程循环,直到处理完所有数据(通常为40-80次迭代)。

每个线程处理8mb的大小相等的输入块(可能在最后一次迭代时除外);每个ByteArrayOutputStream包含1-4 MB,并且输出大小不能提前知道。通常,最早完成和最新完成的CPU绑定线程的运行时间在彼此的20%之内。

我想知道是否有一个IO库(或者我已经错过的java.io或java.nio中的方法)已经做了类似的事情 - 目前第八个线程(IO线程)是大约75%的时间都处于空闲状态,但是我提出的任何方式来缓解这种低效率都会让我觉得太复杂(因此在创建死锁或数据争用方面风险太大);例如,我可以将输入分成4 mb块,然后给七个CPU绑定线程提供两个块,并将一个块提供给IO绑定线程,这理论上将IO线程的空闲时间减少到25% (25%的IO,50%的4 MB大块,25%的空闲),但这是一个脆弱的解决方案,可能无法移植到另一个CPU(这意味着在另一个CPU上,IO绑定的线程可能会变成瓶颈,如果例如,它的运行时间是CPU绑定线程的150%) - 我真的很喜欢自平衡解决方案,因此我不需要手动微调负载平衡。

2 个答案:

答案 0 :(得分:1)

低效率包括在线程8处理任何输出之前等待所有7个输出完成。最好运行7个队列而不是一个队列,即每个源线程一个队列,并按必要的顺序读取它们。这样,当第一个队列有任何数据时,它会被立即处理,而不必等待另一个6;类似的队列2..6。当线程8完成最后一个队列时,它可以开始生成,或者它确实可以这样做而不是等待任何特定队列开始生成。

答案 1 :(得分:0)

我修改了算法如下:

  1. 我没有将输入块直接分配给CPU线程,而是将块放在BlockingQueue中,CPU线程从poll/take处理其工作块
  2. 输出发送到ConcurrentSkipListMap<Integer, ByteArrayOutputStream>
  3. CPU线程只是循环直到取消。 IO线程查看ConcurrentSkipListMap(使用firstKey)以查看是否有任何要写入的数据(我维护一个计数器,指示下一个键应该是什么,以确保输出流被写入然后它检查BlockingQueue的长度以查看是否需要向其添加任何数据(如果queue.size() < N然后我向其添加N个更多块,其中N最初等于12);如果它执行了其中一个或两个IO任务,那么它就会循环,否则它会处理BlockingQueue中的一个块,然后循环。
  4. 除非整个输入已被IO线程处理,否则BlockingQueue不应为空 - 空队列表示需要提高queue.size() < N阈值。因此,CPU线程的逻辑是

    while(!cancel) {
        try {
            Input input = queue.poll();
            if(input == null) {
                log.warn("Empty queue");
                input = queue.take();
            }
            process(input);
        } catch (InterruptedException ex) {
            cancel = true;
        }
    }