服务时间与线程数成正比 [英] Service times directly proportional to number of threads
问题描述
我的系统是具有超线程功能的i5-Dual内核. Windows向我展示了4个处理器.当我一次通过单个线程运行单个优化的CPU绑定任务时,其服务时间始终显示为大约35ms.但是,当我同时将2个任务移交给2个线程时,它们的服务时间显示为大约70ms.我想问一下我的系统有4个处理器,那么如果有2个线程运行teir任务,为什么服务时间在70左右,而2个线程应该在2个处理器上运行而没有任何调度开销呢?代码如下.
My system is i5-Dual core with hyper-threading. Windows show me 4 processors. When i run a single optimized cpu-bound task by a single thread at a time its service time always display arround 35ms. But when i handover 2 tasks to 2 threads simultanously their service times display arround 70ms. I want to ask that my system have 4 processors then why does service times are arround 70 in case of 2 threads running teir tasks whereas 2 threads should run on 2 processors without any scheduling overhead.The codes are as follows.
CPU绑定任务如下.
CPU-Bound Task is as follows.
import java.math.BigInteger;
public class CpuBoundJob implements Runnable {
public void run() {
BigInteger factValue = BigInteger.ONE;
long t1=System.nanoTime();
for ( int i = 2; i <= 2000; i++){
factValue = factValue.multiply(BigInteger.valueOf(i));
}
long t2=System.nanoTime();
System.out.println("Service Time(ms)="+((double)(t2-t1)/1000000));
}
}
运行任务的线程如下.
public class TaskRunner extends Thread {
CpuBoundJob job=new CpuBoundJob();
public void run(){
job.run();
}
}
最后,主类如下.
public class Test2 {
int numberOfThreads=100;//warmup code for JIT
public Test2(){
for(int i=1;i<=numberOfThreads;i++){//warmup code for JIT
TaskRunner t=new TaskRunner();
t.start();
}
try{
Thread.sleep(5000);// wait a little bit
}catch(Exception e){}
System.out.println("Warmed up completed! now start benchmarking");
System.out.println("First run single thread at a time");
try{//wait for the thread to complete
Thread.sleep(5000);
}catch(Exception e){}
//run only one thread at a time
TaskRunner t1=new TaskRunner();
t1.start();
try{//wait for the thread to complete
Thread.sleep(5000);
}catch(Exception e){}
//Now run 2 threads simultanously at a time
System.out.println("Now run 3 thread at a time");
for(int i=1;i<=3;i++){//run 2 thread at a time
TaskRunner t2=new TaskRunner();
t2.start();
}
}
public static void main(String[] args) {
new Test2();
}
最终输出:
热身完成!现在开始进行基准测试,首先在 一个时间Service Time(ms)= 5.829112现在一次运行2个线程 时间(毫秒)= 6.518721服务时间(毫秒)= 10.364269服务 时间(ms)= 10.272689
Warmed up completed! now start benchmarking First run single thread at a time Service Time(ms)=5.829112 Now run 2 thread at a time Service Time(ms)=6.518721 Service Time(ms)=10.364269 Service Time(ms)=10.272689
推荐答案
我在各种情况下都对它进行了计时,并且对任务进行了稍微的修改,一个线程的时间约为45毫秒,两个线程的时间约为60毫秒.因此,即使在此示例中,一个线程也可以在一秒钟内完成大约22个任务,而两个线程可以完成33个任务.
I timed this in a variety of scenarios, and with a slightly modified task, got times of ~45 ms with one thread and ~60 ms for two threads. So, even in this example, in one second, one thread can complete about 22 tasks, but two threads can complete 33 tasks.
但是,如果您运行的任务不会给垃圾收集器带来如此巨大的负担,那么您应该会看到预期的性能提升:两个线程完成了两倍的任务.这是我的测试程序版本.
However, if you run a task that doesn't tax the garbage collector so grievously, you should see the performance increase you expect: two threads complete twice as many tasks. Here is my version of your test program.
请注意,我对您的任务(DirtyTask
)进行了重大更改:n
始终为0,因为您将Math.random()
的结果强制转换为int
(零),并且然后乘以13.
Note that I made one significant change to your task (DirtyTask
): n
was always 0, because you cast the result of Math.random()
to an int
(which is zero), and then multiplied by 13.
然后,我添加了一个CleanTask
,该CleanTask
不会为垃圾收集器生成任何新对象来处理.请在您的计算机上测试并报告结果.在我的身上,我得到了:
Then I added a CleanTask
that doesn't generate any new objects for the garbage collector to handle. Please test and report the results on your machine. On mine, I got this:
Testing "clean" task.
Average task time: one thread = 46 ms; two threads = 45 ms
Testing "dirty" task.
Average task time: one thread = 41 ms; two threads = 62 ms
import java.util.ArrayList;
import java.util.List;
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.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
final class Parallels
{
private static final int RUNS = 10;
public static void main(String... argv)
throws Exception
{
System.out.println("Testing \"clean\" task.");
flavor(CleanTask::new);
System.out.println("Testing \"dirty\" task.");
flavor(DirtyTask::new);
}
private static void flavor(Supplier<Callable<Long>> tasks)
throws InterruptedException, ExecutionException
{
ExecutorService warmup = Executors.newFixedThreadPool(100);
for (int i = 0; i < 100; ++i)
warmup.submit(tasks.get());
warmup.shutdown();
warmup.awaitTermination(1, TimeUnit.DAYS);
ExecutorService workers = Executors.newFixedThreadPool(2);
long t1 = test(1, tasks, workers);
long t2 = test(2, tasks, workers);
System.out.printf("Average task time: one thread = %d ms; two threads = %d ms%n", t1 / (1 * RUNS), t2 / (2 * RUNS));
workers.shutdown();
}
private static long test(int n, Supplier<Callable<Long>> tasks, ExecutorService workers)
throws InterruptedException, ExecutionException
{
long sum = 0;
for (int i = 0; i < RUNS; ++i) {
List<Callable<Long>> batch = new ArrayList<>(n);
for (int t = 0; t < n; ++t)
batch.add(tasks.get());
List<Future<Long>> times = workers.invokeAll(batch);
for (Future<Long> f : times)
sum += f.get();
}
return TimeUnit.NANOSECONDS.toMillis(sum);
}
/**
* Do something on the CPU without creating any garbage, and return the
* elapsed time.
*/
private static class CleanTask
implements Callable<Long>
{
@Override
public Long call()
{
long time = System.nanoTime();
long x = 0;
for (int i = 0; i < 15_000_000; i++)
x ^= ThreadLocalRandom.current().nextLong();
if (x == 0)
throw new IllegalStateException();
return System.nanoTime() - time;
}
}
/**
* Do something on the CPU that creates a lot of garbage, and return the
* elapsed time.
*/
private static class DirtyTask
implements Callable<Long>
{
@Override
public Long call()
{
long time = System.nanoTime();
String s = "";
for (int i = 0; i < 10_000; i++)
s += (int) (ThreadLocalRandom.current().nextDouble() * 13);
if (s.length() == 10_000)
throw new IllegalStateException();
return System.nanoTime() - time;
}
}
}
这篇关于服务时间与线程数成正比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!