我最近在运行此测试时进行了一些Java性能测试,并且非常震惊。我想通过在工作组线程中进行统计来测试并看看我会得到什么样的性能差异...就是当我得到这个非常令人惊讶的结果时。
以下是测试代码:
import org.joda.time.DateTime;
import org.joda.time.Interval;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.*;
/**
* Created by siraj on 1/2/16.
*/
public class WorkerPoolTest {
int SAMPLE_LIMIT = 1000;
DecimalFormat df = new DecimalFormat("#.####");
public static void main(String[] args){
int nTestElements = 100000;
System.out.println("\tLinear\t\t\tNon-Linear");
for (int i = 0;i<25;i++){
// System.out.println("Linear test " + (i+1));
System.out.print((i + 1));
new WorkerPoolTest(false, nTestElements, false);
// System.out.println("Non-linear test " + (i+1));
new WorkerPoolTest(true, nTestElements, false);
System.out.println();
}
System.out.println("Done test");
}
WorkerPoolTest(boolean useWorkerThreads, int testLimit, boolean outPutSampleResults){
DateTime start = new DateTime();
// System.out.println(start);
startWorkerThreads(useWorkerThreads, testLimit, outPutSampleResults);
DateTime end = new DateTime();
// System.out.println(end);
System.out.print("\t " +
df.format( ((double) (new Interval(start, end).toDurationMillis()) /1000) ) + "\t\t");
}
private void startWorkerThreads(boolean userWorkerThreads, int testLimit, boolean outPutSampleResults){
ArrayList<WDataObject> data = new ArrayList<>();
if (userWorkerThreads){
try {
// do fast test
ExecutorService pool = Executors.newFixedThreadPool(6);
int nSeries = 2;
Set<Future<WDataObject>> set = new HashSet<>();
for (int i = 1; i <= testLimit; i ++){
Callable worker = new Worker(i);
Future<WDataObject> future = pool.submit(worker);
set.add(future);
}
for (Future<WDataObject> wdo : set){
data.add(wdo.get());
}
Collections.sort(data);
if (outPutSampleResults)
for (WDataObject ob: data)
{
System.out.println(ob.toString());
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}else{
// do linear test.
for (int i = 1; i <= testLimit; i ++){
WDataObject ob = new WDataObject(i);
for (int s = 1; s <= SAMPLE_LIMIT; s++){
ob.dataList.add((double)i / (double)s);
}
data.add(ob);
}
if (outPutSampleResults)
for (WDataObject ob: data)
{
System.out.println(ob.toString());
}
}
}
class Worker implements Callable{
int i;
Worker(int i){
this.i = i;
}
@Override
public WDataObject call() throws Exception {
WDataObject ob = new WDataObject(i);
for (int s = 1; s <= SAMPLE_LIMIT; s++){
ob.dataList.add((double)i / (double)s);
}
return ob;
}
}
class WDataObject implements Comparable<WDataObject>{
private final int id;
WDataObject(int id){
this.id = id;
}
ArrayList<Double> dataList = new ArrayList<>();
public Integer getID(){
return id;
}
public int getId(){
return id;
}
public String toString(){
String result = "";
for (double data: dataList) {
result += df.format(data) + ",";
}
return result.substring(0, result.length()-1);
}
@Override
public int compareTo(WDataObject o) {
return getID().compareTo(o.getID());
}
}
}
Linear | Non-Linear
1 45.735 | 15.043
2 24.732 | 16.559
3 15.666 | 17.553
4 18.068 | 17.154
5 16.446 | 19.036
6 17.912 | 18.051
7 16.093 | 17.618
8 13.185 | 17.2
9 19.961 | 26.235
10 16.809 | 17.815
11 15.809 | 18.098
12 18.45 | 19.265
当线性计算模型使用单个线程时,这怎么可能?此外,我运行了这个测试并观察了我的系统监视器,并注意到在运行单个嵌入式循环时,我的所有计算机核心都以最大强度使用。这里发生了什么?为什么线性计算算法随后的迭代变得更快?为什么它有时会预先形成同一工作的线程非线性版本呢?
此代码示例使用Joda Time进行时间戳。
此外,我很难将制表空间放入此编辑器中,结果使用了制表符空格。你可以在代码中看到它。
答案 0 :(得分:1)
您的测试真正衡量的是...对象分配性能。
每次执行ob.dataList.add((double) i / (double) s);
时,您都会自动装箱,并且您正在创建一个新的Double对象。并且因为您将此添加到转义本地范围的列表中,所以HotSpot编译器不能将堆栈分配作为优化。所以它必须在堆上进行分配,这是一个相对昂贵的操作,需要在线程之间进行一些协调,因此它会降低您的多线程性能。
第1步让您的算法更真实:将ArrayList<Double> dataList = new ArrayList<>();
替换为:
double[] dataList = new double[SAMPLE_LIMIT];
之后,你的&#34;非线性&#34;版本一致地优于线性版本。
其次,划分是一种非常便宜的操作,因此无论如何,无论您使用多少线程,您都主要测量内存写入并且内存总线吞吐量有限。
如果用以下内容替换当前代码:
double sum = 0;
for (int s = 1; s <= SAMPLE_LIMIT; s++) {
sum += (double) i / (double) s;
}
ob.dataList[0] = sum;
然后您会发现您的非线性版本的性能优于线性版本4到6,这是您对固定大小为6的线程池所期望的。
答案 1 :(得分:0)
这不是您问题的答案,只是确认我得到的结果相同。
我删除了冗余代码,并测量了两种情况下完全相同的代码执行时间。结果不会在多次运行中发生变化,并且在订单被撤消时会排除垃圾收集或测试期间任何与操作系统相关的CPU峰值。
此处修改过的代码。
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class TestPerf {
int SAMPLE_LIMIT = 10000;
DecimalFormat df = new DecimalFormat("#.####");
public static final int TEST_COUNT = 10;
public static void main(String[] args) {
TestPerf main = new TestPerf();
int nTestElements = 10000;
System.out.println("\tLinear\t\t\t\tNon-Linear");
for (int i = 0; i < TEST_COUNT; i++) {
System.out.print((i + 1));
main.startWorkerThreads(false, nTestElements, false);
main.startWorkerThreads(true, nTestElements, false);
System.out.println("");
}
System.out.println("Reversed tests");
System.out.println("\tNon Linear\t\t\t\tLinear");
for (int i = 0; i < TEST_COUNT; i++) {
System.out.print((i + 1));
main.startWorkerThreads(true, nTestElements, false);
main.startWorkerThreads(false, nTestElements, false);
System.out.println("");
}
System.out.println("Done test");
}
private void startWorkerThreads(boolean userWorkerThreads, int testLimit, boolean outPutSampleResults) {
if (userWorkerThreads) {
try {
// do fast test
ExecutorService pool = Executors.newFixedThreadPool(6);
Set<Future<Long>> futureSet = new HashSet<Future<Long>>();
for (int i = 1; i <= testLimit; i++) {
Callable<Long> worker = new Worker(i);
futureSet.add(pool.submit(worker));
}
pool.shutdown();
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
//checking futures after all have returned, don't want to wait on each
long executionTime = 0;
for(Future<Long> future : futureSet) {
executionTime += future.get();
}
System.out.printf("\tnon linear = %f\t", (executionTime / 1e9));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
} else {
// do linear test.
long timeDelta = 0;
for (int i = 1; i <= testLimit; i++) {
long startTime = System.nanoTime();
WDataObject ob = new WDataObject(i);
for (int s = 1; s <= SAMPLE_LIMIT; s++) {
ob.dataList.add((double) i / (double) s);
}
long endTime = System.nanoTime();
timeDelta += (endTime - startTime);
}
System.out.printf("\tlinear = %f\t",(timeDelta / 1e9));
}
}
class Worker implements Callable<Long> {
int i;
Worker(int i) {
this.i = i;
}
@Override
public Long call() throws Exception {
long startTime = System.nanoTime();
WDataObject ob = new WDataObject(i);
for (int s = 1; s <= SAMPLE_LIMIT; s++) {
ob.dataList.add((double) i / (double) s);
}
long endTime = System.nanoTime();
return (endTime - startTime);
}
}
class WDataObject implements Comparable<WDataObject> {
private final int id;
ArrayList<Double> dataList = new ArrayList<>();
WDataObject(int id) {
this.id = id;
}
public Integer getID() {
return id;
}
public int getId() {
return id;
}
public String toString() {
String result = "";
for (double data : dataList) {
result += df.format(data) + ",";
}
return result.substring(0, result.length() - 1);
}
@Override
public int compareTo(WDataObject o) {
return getID().compareTo(o.getID());
}
}
}
注意:此测试是在向执行程序提交10000个任务的情况下运行的,不仅如此,它只需要花费很多时间,但我怀疑结果是否会发生变化。
<强>输出强>
Linear Non-Linear
1 linear = 1.261564 non linear = 3.831899
2 linear = 1.098359 non linear = 3.677221
3 linear = 1.315108 non linear = 3.542210
4 linear = 1.267752 non linear = 3.415670
5 linear = 1.249890 non linear = 3.387447
6 linear = 1.297200 non linear = 4.244616
7 linear = 1.328806 non linear = 4.821367
8 linear = 1.362364 non linear = 4.582840
9 linear = 1.392996 non linear = 5.169028
10 linear = 1.319172 non linear = 4.734327
Reversed tests
Non Linear Linear
1 non linear = 5.033875 linear = 1.329440
2 non linear = 4.547303 linear = 1.291331
3 non linear = 4.613079 linear = 1.353841
4 non linear = 4.618064 linear = 1.314747
5 non linear = 4.580547 linear = 1.313031
6 non linear = 5.371241 linear = 1.338901
7 non linear = 5.194418 linear = 1.361951
8 non linear = 4.521603 linear = 1.251608
9 non linear = 4.474672 linear = 1.304659
10 non linear = 4.580605 linear = 1.349442
Done test
修改 **
通过 @Erwin Boldwidt
确认调查结果这里的代码是double []数组而不是ArrayList
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class TestPerf {
int SAMPLE_LIMIT = 10000;
DecimalFormat df = new DecimalFormat("#.####");
public static final int TEST_COUNT = 10;
public static void main(String[] args) {
TestPerf main = new TestPerf();
int nTestElements = 10000;
System.out.println("\tLinear\t\t\t\tNon-Linear");
for (int i = 0; i < TEST_COUNT; i++) {
System.out.print((i + 1));
main.startWorkerThreads(false, nTestElements, false);
main.startWorkerThreads(true, nTestElements, false);
System.out.println("");
}
System.out.println("Reversed tests");
System.out.println("\tNon Linear\t\t\t\tLinear");
for (int i = 0; i < TEST_COUNT; i++) {
System.out.print((i + 1));
main.startWorkerThreads(true, nTestElements, false);
main.startWorkerThreads(false, nTestElements, false);
System.out.println("");
}
System.out.println("Done test");
}
private void startWorkerThreads(boolean userWorkerThreads, int testLimit, boolean outPutSampleResults) {
if (userWorkerThreads) {
try {
// do fast test
ExecutorService pool = Executors.newFixedThreadPool(6);
Set<Future<Long>> futureSet = new HashSet<Future<Long>>();
for (int i = 1; i <= testLimit; i++) {
Callable<Long> worker = new Worker(i);
futureSet.add(pool.submit(worker));
}
pool.shutdown();
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
//checking futures after all have returned, don't want to wait on each
long executionTime = 0;
for(Future<Long> future : futureSet) {
executionTime += future.get();
}
System.out.printf("\tnon linear = %f\t", (executionTime / 1e9));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
} else {
// do linear test.
long timeDelta = 0;
for (int i = 1; i <= testLimit; i++) {
long startTime = System.nanoTime();
WDataObject ob = new WDataObject(i);
for (int s = 1; s <= SAMPLE_LIMIT; s++) {
ob.dataList[s-1] = (double) i / (double)s;
}
long endTime = System.nanoTime();
timeDelta += (endTime - startTime);
}
System.out.printf("\tlinear = %f\t",(timeDelta / 1e9));
}
}
class Worker implements Callable<Long> {
int i;
Worker(int i) {
this.i = i;
}
@Override
public Long call() throws Exception {
long startTime = System.nanoTime();
WDataObject ob = new WDataObject(i);
for (int s = 1; s <= SAMPLE_LIMIT; s++) {
ob.dataList[s-1] = (double) i / (double)s;
}
long endTime = System.nanoTime();
return (endTime - startTime);
}
}
class WDataObject implements Comparable<WDataObject> {
private final int id;
double[] dataList = new double[SAMPLE_LIMIT];
WDataObject(int id) {
this.id = id;
}
public Integer getID() {
return id;
}
public int getId() {
return id;
}
public String toString() {
String result = "";
for (double data : dataList) {
result += df.format(data) + ",";
}
return result.substring(0, result.length() - 1);
}
@Override
public int compareTo(WDataObject o) {
return getID().compareTo(o.getID());
}
}
}
以下是更改后的输出。
Linear Non-Linear
1 linear = 0.954303 non linear = 1.582391
2 linear = 0.926418 non linear = 1.581830
3 linear = 0.600321 non linear = 1.454271
4 linear = 0.599520 non linear = 1.606025
5 linear = 0.608767 non linear = 1.529756
6 linear = 0.592436 non linear = 1.546165
7 linear = 0.587736 non linear = 1.525757
8 linear = 0.593176 non linear = 1.599800
9 linear = 0.586822 non linear = 1.452616
10 linear = 0.613389 non linear = 1.497857
Reversed tests
Non Linear Linear
1 non linear = 1.654733 linear = 0.591032
2 non linear = 1.554027 linear = 0.600774
3 non linear = 1.492715 linear = 0.587769
4 non linear = 1.574326 linear = 0.603979
5 non linear = 1.536751 linear = 0.590862
6 non linear = 1.628588 linear = 0.585333
7 non linear = 1.591440 linear = 0.604465
8 non linear = 1.444600 linear = 0.587350
9 non linear = 1.562186 linear = 0.607937
10 non linear = 1.559000 linear = 0.586294
Done test
现在非线性部分的工作速度比线性部分快3倍。