我要实现的任务是使用多个线程在设定的间隔中找到数字的Collatz序列,并查看与一个线程相比有多少改进。
但是无论我选择2个线程,一个线程总是总是更快(编辑.2个线程更快,但是4个线程比1个线程慢,而且速度不算多,我也不知道为什么。(我什至可以说线程越多,速度越慢)。我希望有人可以解释。也许我做错了。
下面是我到目前为止编写的代码。我正在使用ThreadPoolExecutor执行任务(一个任务=一个Collatz序列,一个间隔中的一个数字)。
Collatz类:
public class ParallelCollatz implements Runnable {
private long result;
private long inputNum;
public long getResult() {
return result;
}
public void setResult(long result) {
this.result = result;
}
public long getInputNum() {
return inputNum;
}
public void setInputNum(long inputNum) {
this.inputNum = inputNum;
}
public void run() {
//System.out.println("number:" + inputNum);
//System.out.println("Thread:" + Thread.currentThread().getId());
//int j=0;
//if(Thread.currentThread().getId()==11) {
// ++j;
// System.out.println(j);
//}
long result = 1;
//main recursive computation
while (inputNum > 1) {
if (inputNum % 2 == 0) {
inputNum = inputNum / 2;
} else {
inputNum = inputNum * 3 + 1;
}
++result;
}
// try {
//Thread.sleep(10);
//} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
//}
this.result=result;
return;
}
}
运行线程的主类(是的,我现在创建两个具有相同编号的列表,因为使用一个线程运行后,初始值会丢失):
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(1);
ThreadPoolExecutor executor2 = (ThreadPoolExecutor)Executors.newFixedThreadPool(4);
List<ParallelCollatz> tasks = new ArrayList<ParallelCollatz>();
for(int i=1; i<=1000000; i++) {
ParallelCollatz task = new ParallelCollatz();
task.setInputNum((long)(i+1000000));
tasks.add(task);
}
long startTime = System.nanoTime();
for(int i=0; i<1000000; i++) {
executor.execute(tasks.get(i));
}
executor.shutdown();
boolean tempFirst=false;
try {
tempFirst =executor.awaitTermination(5, TimeUnit.HOURS);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("tempFirst " + tempFirst);
long endTime = System.nanoTime();
long durationInNano = endTime - startTime;
long durationInMillis = TimeUnit.NANOSECONDS.toMillis(durationInNano); //Total execution time in nano seconds
System.out.println("laikas " +durationInMillis);
List<ParallelCollatz> tasks2 = new ArrayList<ParallelCollatz>();
for(int i=1; i<=1000000; i++) {
ParallelCollatz task = new ParallelCollatz();
task.setInputNum((long)(i+1000000));
tasks2.add(task);
}
long startTime2 = System.nanoTime();
for(int i=0; i<1000000; i++) {
executor2.execute(tasks2.get(i));
}
executor2.shutdown();
boolean temp =false;
try {
temp=executor2.awaitTermination(5, TimeUnit.HOURS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("temp "+ temp);
long endTime2 = System.nanoTime();
long durationInNano2 = endTime2 - startTime2;
long durationInMillis2 = TimeUnit.NANOSECONDS.toMillis(durationInNano2); //Total execution time in nano seconds
System.out.println("laikas2 " +durationInMillis2);
例如,使用一个线程运行,它可以在3280毫秒内完成。用两个线程运行3437ms。我应该考虑使用其他并发结构来计算每个元素吗?
编辑 澄清。我不是要并行化各个序列,而是要使每个数字具有序列时要间隔一个数字。(与其他数字无关)
EDIT2
今天,我在具有6个核心和12个逻辑处理器的优秀PC上运行了该程序,问题仍然存在。有谁知道问题可能在哪里?我还更新了我的代码。 4个线程由于某些原因比2个线程差(甚至比1个线程差)。我也应用了答案中给出的内容,但没有任何变化。
另一个编辑 我注意到的是,如果将Thread.sleep(1)放入ParallelCollatz方法中,则性能会随着线程数的增加而逐渐提高。也许这个细节告诉别人出了什么问题?但是,如果没有Thread.Sleep(1),无论我执行多少任务,第二个线程的执行速度最快,第二个线程的执行速度最快,而其他线程则挂起了类似的毫秒数,但都比1和2个线程慢。
新编辑 我还尝试在Runnable类的run()方法中放置更多任务(用于计算不是1而是10或100个Collatz序列的循环),以便线程本身可以完成更多工作。不幸的是,这也没有帮助。 也许我启动任务不正确?任何想法吗?
编辑 因此,在向run方法添加更多任务之后,似乎可以对其进行一些修复,但是对于更多线程,该问题仍然保持8+。我仍然想知道这是因为创建和运行线程比执行任务花费更多的时间吗?还是我应该针对这个问题创建新帖子?
答案 0 :(得分:2)
您不是在等待任务完成,而是在衡量将其提交给执行者所花费的时间。
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at android.view.View android.view.LayoutInflater.inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean) (LayoutInflater.java:515)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at android.view.View android.view.LayoutInflater.inflate(int, android.view.ViewGroup, boolean) (LayoutInflater.java:423)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at android.view.View android.view.LayoutInflater.inflate(int, android.view.ViewGroup) (LayoutInflater.java:374)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at android.view.ViewGroup android.support.v7.app.AppCompatDelegateImpl.createSubDecor() (AppCompatDelegateImpl.java:607)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.support.v7.app.AppCompatDelegateImpl.ensureSubDecor() (AppCompatDelegateImpl.java:518)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.support.v7.app.AppCompatDelegateImpl.setContentView(int) (AppCompatDelegateImpl.java:466)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.support.v7.app.AppCompatActivity.setContentView(int) (AppCompatActivity.java:140)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void com.example.hellojni.HelloJni.onCreate(android.os.Bundle) (HelloJni.java:75)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.app.Activity.performCreate(android.os.Bundle, android.os.PersistableBundle) (Activity.java:7009)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.app.Activity.performCreate(android.os.Bundle) (Activity.java:7000)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.app.Instrumentation.callActivityOnCreate(android.app.Activity, android.os.Bundle) (Instrumentation.java:1214)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:2731)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:2856)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.app.ActivityThread.-wrap11(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:-1)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1589)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:106)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.os.Looper.loop() (Looper.java:164)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6494)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run() (RuntimeInit.java:438)
2019-04-27 21:04:25.650 21326-21326/com.example.hellojni I/zygote: at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:807)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: Rejecting re-init on previously-failed class java.lang.Class<android.support.v4.view.ViewCompat$OnUnhandledKeyEventListenerWrapper>: java.lang.NoClassDefFoundError: Failed resolution of: Landroid/view/View$OnUnhandledKeyEventListener;
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at void android.support.v4.view.ViewCompat.setBackground(android.view.View, android.graphics.drawable.Drawable) (ViewCompat.java:2341)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at void android.support.v7.widget.ActionBarContainer.<init>(android.content.Context, android.util.AttributeSet) (ActionBarContainer.java:62)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[]) (Constructor.java:-2)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[]) (Constructor.java:334)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at android.view.View android.view.LayoutInflater.createView(java.lang.String, java.lang.String, android.util.AttributeSet) (LayoutInflater.java:647)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at android.view.View android.view.LayoutInflater.createViewFromTag(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet, boolean) (LayoutInflater.java:790)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at android.view.View android.view.LayoutInflater.createViewFromTag(android.view.View, java.lang.String, android.content.Context, android.util.AttributeSet) (LayoutInflater.java:730)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at void android.view.LayoutInflater.rInflate(org.xmlpull.v1.XmlPullParser, android.view.View, android.content.Context, android.util.AttributeSet, boolean) (LayoutInflater.java:863)
2019-04-27 21:04:25.651 21326-21326/com.example.hellojni I/zygote: at void android.view.LayoutInflater.rInflateChildren(org.xmlpull.v1.XmlPullParser, android.view.View, android.util.AttributeSet, boolean) (LayoutInflater.java:824)
不会等待所有任务完成。您需要在此之后致电executor.shutdown()
。
executor.awaitTermination
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#shutdown()
更新 我相信我们的测试方法是有缺陷的。我在我的机器(1个处理器,2个内核,4个逻辑处理器)上重复了测试,并且每次运行所花费的时间差异很大。
我相信以下是主要原因:
要对此进行测试,我将您的测试转换为JMH。 特别是:
我在下面收到的结果符合我的期望:一个内核在主线程中等待,工作在单个内核上执行,数量几乎相同。
executor.shutdown();
executor.awaitTermination(5, TimeUnit.HOURS);
更新的代码:
Benchmark Mode Cnt Score Error Units
SpeedTest.multipleThreads avgt 20 559.996 ± 20.181 ms/op
SpeedTest.singleThread avgt 20 562.048 ± 16.418 ms/op
和基准本身:
public class ParallelCollatz implements Callable<Long> {
private final long inputNumInit;
public ParallelCollatz(long inputNumInit) {
this.inputNumInit = inputNumInit;
}
@Override
public Long call() {
long result = 1;
long inputNum = inputNumInit;
//main recursive computation
while (inputNum > 1) {
if (inputNum % 2 == 0) {
inputNum = inputNum / 2;
} else {
inputNum = inputNum * 3 + 1;
}
++result;
}
return result;
}
}