Java多线程模板基准测试

3

我试图对一个简单的Java应用程序进行多线程基准测试,将迭代器的每个元素转换为另一个元素。

在下面的这些方法中(Java 8并行流,使用lambda运算符的常规多线程),哪种方法效率最高?根据下面的输出结果,好像并行流和传统的多线程一样好,是吗?

下面代码(你需要将alice.txt替换为另一个文件)的输出:

153407    30420

时间(毫秒) - 4826

153407    30420

时间(毫秒) - 37908

153407    30420

时间(毫秒) - 37947

153407    30420

时间(毫秒) - 4839

public class ParallelProcessingExample {

public static void main(String[] args) throws IOException{
    String contents = new String(Files.readAllBytes(
            Paths.get("impatient/code/ch2/alice.txt")), StandardCharsets.UTF_8);
    List<String> words = Arrays.asList(contents.split("[\\P{L}]+"));

    long t=System.currentTimeMillis();
    Stream<String> wordStream = words.parallelStream().map(x->process(x));
    String[] out0=wordStream.toArray(String[]::new);
    System.out.println(String.join("-", out0).length()+"\t"+out0.length);
    System.out.println("time in ms - "+(System.currentTimeMillis()-t));

    t=System.currentTimeMillis();
    wordStream = words.stream().map(x->process(x));
    String[] out1=wordStream.toArray(String[]::new);
    System.out.println(String.join("-", out1).length()+"\t"+out1.length);
    System.out.println("time in ms - "+(System.currentTimeMillis()-t));


    t=System.currentTimeMillis();
    String[] out2=new String[words.size()];
    for(int j=0;j<words.size();j++){
        out2[j]=process(words.get(j));
    }
    System.out.println(String.join("-", out2).length()+"\t"+out2.length);
    System.out.println("time in ms - "+(System.currentTimeMillis()-t));

    t=System.currentTimeMillis();
    int n = Runtime.getRuntime().availableProcessors();
    String[] out3=new String[words.size()];
    try {
        ExecutorService pool = Executors.newCachedThreadPool();
        for(int i=0;i<n;i++){
            int from=i*words.size()/n;
            int to=(i+1)*words.size()/n;
            pool.submit(() -> {
                for(int j=from;j<to;j++){
                    out3[j]=process(words.get(j));
                }
            });
        }
        pool.shutdown();
        pool.awaitTermination(1, TimeUnit.HOURS);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println(String.join("-", out3).length()+"\t"+out3.length);
    System.out.println("time in ms - "+(System.currentTimeMillis()-t));

}

private static String process(String x) {
    try {
        TimeUnit.NANOSECONDS.sleep(1);
        //Thread.sleep(1);                 //1000 milliseconds is one second.
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }
    return x.toUpperCase();
}

}

考虑到它询问的是优化性能特征而不是构建功能,因此最好在Code Review上进行。 - Nathan Tuggy
1
你面临的一个问题是性能方面已经出现了问题,你没有考虑到JIT。 - fge
@Nathan,我也把它放在代码审查中了。但错误问题可能在这里是相关的。 - sid
@fge,我没听懂你的意思。你是在说异常错误还是性能问题? - sid
1
性能问题。JIT 只会在某些代码执行一定次数后才会启动;你完全没有考虑到这一点。这就是为什么像 jmh 或 caliper 这样的工具存在的原因。 - fge
1个回答

1
Java 8并行流(通常情况下)可以与手动多线程一样好,但这也取决于具体的情况。
如果您太早关闭池,则会收到RejectedExecutionException:应在for循环之外调用pool.shutdown()。
Java 8并行流的一个巨大优势是您不必担心这些事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接