线程 fork(10)
package org.openjdk.jmh.samples; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.lang.management.ManagementFactory; import java.util.concurrent.TimeUnit; /** * 我们发现进程pid是一样的,初步推测fork(10),代表新开10个进程 */ @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS) //预热次数和时间 @Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS) //测试次数和时间 public class JMHSample_12_Forking { @Benchmark @Fork(10) //通过源码我们可以直到,10代表 10 fork public int measure_1_c1() { return 1; } @Setup(Level.Trial) // 在基准执行之前先打印pid。 public void setup() { printProcessID("setup"); } public static void printProcessID(String name) { //打印pid System.out.println(); System.out.println("--------------"); System.out.println(name + " pid is : " + ManagementFactory.getRuntimeMXBean().getName()); System.out.println("--------------"); System.out.println(); } public static void main(String[] args) throws RunnerException { printProcessID("main"); // 执行main方法的时候打印pid Options opt = new OptionsBuilder() .include(JMHSample_12_Forking.class.getSimpleName()) .build(); new Runner(opt).run(); //当他启动的时候,才会开始运行基准 } }
fork() 默认值是-1,但效果等于传5
package org.openjdk.jmh.samples; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.lang.management.ManagementFactory; import java.util.concurrent.TimeUnit; /** * 我们发现进程pid是一样的,初步推测fork),代表新开5个进程 */ @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS) //预热次数和时间 @Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS) //测试次数和时间 public class JMHSample_12_Forking { @Benchmark @Fork() //默认是-1 实际传5 public int measure_1_c1() { return 1; } @Setup(Level.Trial) // 在基准执行之前先打印pid。 public void setup() { printProcessID("setup"); } public static void printProcessID(String name) { //打印pid System.out.println(); System.out.println("--------------"); System.out.println(name + " pid is : " + ManagementFactory.getRuntimeMXBean().getName()); System.out.println("--------------"); System.out.println(); } public static void main(String[] args) throws RunnerException { printProcessID("main"); // 执行main方法的时候打印pid Options opt = new OptionsBuilder() .include(JMHSample_12_Forking.class.getSimpleName()) .build(); new Runner(opt).run(); //当他启动的时候,才会开始运行基准 } }
forking 源码
在同一个JVM中,不同的基准会相互影响的。
package org.openjdk.jmh.samples; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit; /** * 在同一个JVM线程中,我们发现各个基准是相互影响的 */ @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //预热次数和时间 @Measurement(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间 public class JMHSample_12_Forking { public interface Counter { //匿名内部类 int inc(); } public static class Counter1 implements Counter { //实现接口1 private int x; @Override public int inc() { return x++; } } public static class Counter2 implements Counter { //实现接口2 private int x; @Override public int inc() { return x++; } } public int measure(Counter c) { //方法 int s = 0; for (int i = 0; i < 10; i++) { s += c.inc(); } return s; } Counter c1 = new Counter1(); Counter c2 = new Counter2(); @Benchmark @Fork(0) public int measure_1_c1() { //与main方法同进程 return measure(c1); } @Benchmark @Fork(0) public int measure_2_c2() { //与main方法同进程 return measure(c2); } @Benchmark @Fork(0) public int measure_3_c1_again() { //与main方法同进程 return measure(c1); } @Benchmark @Fork(1) public int measure_4_forked_c1() {//与main方法不同进程 return measure(c1); } @Benchmark @Fork(1) public int measure_5_forked_c2() { //与main方法不同进程 return measure(c2); } public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(JMHSample_12_Forking.class.getSimpleName()) .build(); new Runner(opt).run(); } }
14.什么时候使用fork
大数样本: 大数法则当我们的样本足够多的时候,我们抽取的越多,那么就越接近平均值。 所以我们多开点线程就可以多取样本。
package org.openjdk.jmh.samples; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit; /** * 大数样本: 大数法则当我们的样本足够多的时候,我们抽取的越多,那么就越接近平均值。 */ @State(Scope.Thread) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) @Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //预热次数和时间 @Measurement(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间 public class JMHSample_13_RunToRun { @State(Scope.Thread) public static class SleepyState { //定义一个静态内部类 public long sleepTime; @Setup public void setup() { sleepTime = (long) (Math.random() * 1000); System.out.println("---------------"); System.out.println("sleepTime-> "+sleepTime); System.out.println("---------------"); } //生成一个随机休眠数 } /* * Now, we will run this different number of times. */ @Benchmark @Fork(1) public void baseline(SleepyState s) throws InterruptedException { TimeUnit.MILLISECONDS.sleep(s.sleepTime); } @Benchmark @Fork(5) public void fork_1(SleepyState s) throws InterruptedException { TimeUnit.MILLISECONDS.sleep(s.sleepTime); } @Benchmark @Fork(20) public void fork_2(SleepyState s) throws InterruptedException { TimeUnit.MILLISECONDS.sleep(s.sleepTime); } public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(JMHSample_13_RunToRun.class.getSimpleName()) .warmupIterations(0) .measurementIterations(3) .build(); new Runner(opt).run(); } }