Can you give me some idea how to optimize the switch
statements, maybe a for
or do while
loop? Which is faster, switch
or for
/while
loop?
public class CalculateTheValueOfE {
static long start1 = System.currentTimeMillis();
static int numberOfThread = 4;
private static int precision = 0;
private static int threadCount = 0;
private static String defaultFile = null;
static BigDecimal result = BigDecimal.ONE;
public static BigDecimal factorial(int x) {
BigDecimal prod = new BigDecimal("1");
for (int i = x; i > 1; i--) {
prod = prod.multiply(new BigDecimal(i));
}
return prod;
}
public static Runnable getRunner(final int from, final int to) {
Runnable runner = new Runnable() {
@Override
public void run() {
BigDecimal e = BigDecimal.valueOf(0);
for (int i = from; i < to; i++) {
e = e.add(BigDecimal.valueOf(3 * 3 * i * i + 1).divide(factorial(3 * i), new MathContext(1000, RoundingMode.HALF_UP)));
}
addResult(e);
}
};
return runner;
}
public static synchronized void addResult(BigDecimal e) {
result = result.add(e);
}
public static void main(String[] args) throws InterruptedException, IOException {
//Thread tr[] = new Thread[threadCount];
// Runnable r[] = new Runnable[numberOfThread];
File file = new File("result.txt");
FileOutputStream fis = new FileOutputStream(file);
PrintStream out = new PrintStream(fis);
System.setOut(out);
for (int i = 0; i < args.length; i++) {
System.out.println(i + " " + args[i]);
}
threadCount = Integer.valueOf(args[1]);
precision = Integer.valueOf(args[3]);
defaultFile = args[5];
System.out.println("Number of threads: " + threadCount + " precision: " + precision + " default file to save the result: " + defaultFile);
//String numberOfThreads = args[1];
//String precision = args[3];
//String defaultFile = args[5];
int calculation = precision / threadCount;
/* for (int i = 1; i<= precision; i+=calculation){
Runnable r = getRunner(i, calculation + 1);
Thread t = new Thread(r);
t.start();
t.join();
i=250;
}*/
switch (threadCount) {
case 1:
Runnable r1 = getRunner(1, precision);
Thread t1 = new Thread(r1);
t1.start();
t1.join();
break;
case 2:
r1 = getRunner(1, precision / 2 + 1);
Runnable r2 = getRunner(precision / 2 + 1, precision);
t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
t1.join();
t2.join();
break;
case 3:
r1 = getRunner(1, precision / 3 + 1);
r2 = getRunner(precision / 3 + 1, 2 * precision / 3 + 1);
Runnable r3 = getRunner(2 * precision / 3 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
Thread t3 = new Thread(r3);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
break;
case 4:
r1 = getRunner(1, precision / 4 + 1);
r2 = getRunner(precision / 4 + 1, 2 * precision / 4 + 1);
r3 = getRunner(2 * precision / 4 + 1, 3 * precision / 4 + 1);
Runnable r4 = getRunner(3 * precision / 4 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
Thread t4 = new Thread(r4);
t1.start();
t2.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
break;
case 5:
r1 = getRunner(1, precision / 5 + 1);
r2 = getRunner(precision / 5 + 1, 2 * precision / 5 + 1);
r3 = getRunner(2 * precision / 5 + 1, 3 * precision / 5 + 1);
r4 = getRunner(3 * precision / 5 + 1, 4 * precision / 5 + 1);
Runnable r5 = getRunner(4 * precision / 5 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
t4 = new Thread(r4);
Thread t5 = new Thread(r5);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
break;
case 6:
r1 = getRunner(1, precision / 6 + 1);
r2 = getRunner(precision / 6 + 1, 2 * precision / 6 + 1);
r3 = getRunner(2 * precision / 6 + 1, 3 * precision / 6 + 1);
r4 = getRunner(3 * precision / 6 + 1, 4 * precision / 6 + 1);
r5 = getRunner(4 * precision / 6 + 1, 5 * precision / 6 + 1);
Runnable r6 = getRunner(5 * precision / 6 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
t4 = new Thread(r4);
t5 = new Thread(r5);
Thread t6 = new Thread(r6);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
break;
case 7:
r1 = getRunner(1, precision / 7 + 1);
r2 = getRunner(precision / 7 + 1, 2 * precision / 7 + 1);
r3 = getRunner(2 * precision / 7 + 1, 3 * precision / 7 + 1);
r4 = getRunner(3 * precision / 7 + 1, 4 * precision / 7 + 1);
r5 = getRunner(4 * precision / 7 + 1, 5 * precision / 7 + 1);
r6 = getRunner(5 * precision / 7 + 1, 6 * precision / 7 + 1);
Runnable r7 = getRunner(6 * precision / 7 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
t4 = new Thread(r4);
t5 = new Thread(r5);
t6 = new Thread(r6);
Thread t7 = new Thread(r7);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
break;
case 8:
r1 = getRunner(1, precision / 8 + 1);
r2 = getRunner(precision / 8 + 1, 2 * precision / 8 + 1);
r3 = getRunner(2 * precision / 8 + 1, 3 * precision / 8 + 1);
r4 = getRunner(3 * precision / 8 + 1, 4 * precision / 8 + 1);
r5 = getRunner(4 * precision / 8 + 1, 5 * precision / 8 + 1);
r6 = getRunner(5 * precision / 8 + 1, 6 * precision / 8 + 1);
r7 = getRunner(6 * precision / 8 + 1, 7 * precision / 8 + 1);
Runnable r8 = getRunner(7 * precision / 8 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
t4 = new Thread(r4);
t5 = new Thread(r5);
t6 = new Thread(r6);
t7 = new Thread(r7);
Thread t8 = new Thread(r8);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
t8.join();
break;
case 12:
r1 = getRunner(1, precision / 12 + 1);
r2 = getRunner(precision / 12 + 1, 2 * precision / 12 + 1);
r3 = getRunner(2 * precision / 12 + 1, 3 * precision / 12 + 1);
r4 = getRunner(3 * precision / 12 + 1, 4 * precision / 12 + 1);
r5 = getRunner(4 * precision / 12 + 1, 5 * precision / 12 + 1);
r6 = getRunner(5 * precision / 12 + 1, 6 * precision / 12 + 1);
r7 = getRunner(6 * precision / 12 + 1, 7 * precision / 12 + 1);
r8 = getRunner(7 * precision / 12 + 1, 8 * precision / 12 + 1);
Runnable r9 = getRunner(8 * precision / 12 + 1, 9 * precision / 12 + 1);
Runnable r10 = getRunner(9 * precision / 12 + 1, 10 * precision / 12 + 1);
Runnable r11 = getRunner(10 * precision / 12 + 1, 11 * precision / 12 + 1);
Runnable r12 = getRunner(11 * precision / 12 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
t4 = new Thread(r4);
t5 = new Thread(r5);
t6 = new Thread(r6);
t7 = new Thread(r7);
t8 = new Thread(r8);
Thread t9 = new Thread(r9);
Thread t10 = new Thread(r10);
Thread t11 = new Thread(r11);
Thread t12 = new Thread(r12);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
t9.start();
t10.start();
t11.start();
t12.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
t8.join();
t9.join();
t10.join();
t11.join();
t12.join();
break;
case 16:
r1 = getRunner(1, precision / 16 + 1);
r2 = getRunner(precision / 16 + 1, 2 * precision / 16 + 1);
r3 = getRunner(2 * precision / 16 + 1, 3 * precision / 16 + 1);
r4 = getRunner(3 * precision / 16 + 1, 4 * precision / 16 + 1);
r5 = getRunner(4 * precision / 16 + 1, 5 * precision / 16 + 1);
r6 = getRunner(5 * precision / 16 + 1, 6 * precision / 16 + 1);
r7 = getRunner(6 * precision / 16 + 1, 7 * precision / 16 + 1);
r8 = getRunner(7 * precision / 16 + 1, 8 * precision / 16 + 1);
r9 = getRunner(8 * precision / 16 + 1, 9 * precision / 16 + 1);
r10 = getRunner(9 * precision / 16 + 1, 10 * precision / 16 + 1);
r11 = getRunner(10 * precision / 16 + 1, 11 * precision / 16 + 1);
r12 = getRunner(11 * precision / 16 + 1, 12 * precision / 16 + 1);
Runnable r13 = getRunner(12 * precision / 16 + 1, 13 * precision / 16 + 1);
Runnable r14 = getRunner(13 * precision / 16 + 1, 14 * precision / 16 + 1);
Runnable r15 = getRunner(14 * precision / 16 + 1, 15 * precision / 16 + 1);
Runnable r16 = getRunner(15 * precision / 16 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
t4 = new Thread(r4);
t5 = new Thread(r5);
t6 = new Thread(r6);
t7 = new Thread(r7);
t8 = new Thread(r8);
t9 = new Thread(r9);
t10 = new Thread(r10);
t11 = new Thread(r11);
t12 = new Thread(r12);
Thread t13 = new Thread(r13);
Thread t14 = new Thread(r14);
Thread t15 = new Thread(r15);
Thread t16 = new Thread(r16);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
t9.start();
t10.start();
t11.start();
t12.start();
t13.start();
t14.start();
t15.start();
t16.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
t8.join();
t9.join();
t10.join();
t11.join();
t12.join();
t13.join();
t14.join();
t15.join();
t16.join();
break;
case 20:
r1 = getRunner(1, precision / 20 + 1);
r2 = getRunner(precision / 20 + 1, 2 * precision / 20 + 1);
r3 = getRunner(2 * precision / 20 + 1, 3 * precision / 20 + 1);
r4 = getRunner(3 * precision / 20 + 1, 4 * precision / 20 + 1);
r5 = getRunner(4 * precision / 20 + 1, 5 * precision / 20 + 1);
r6 = getRunner(5 * precision / 20 + 1, 6 * precision / 20 + 1);
r7 = getRunner(6 * precision / 20 + 1, 7 * precision / 20 + 1);
r8 = getRunner(7 * precision / 20 + 1, 8 * precision / 20 + 1);
r9 = getRunner(8 * precision / 20 + 1, 9 * precision / 20 + 1);
r10 = getRunner(9 * precision / 20 + 1, 10 * precision / 20 + 1);
r11 = getRunner(10 * precision / 20 + 1, 11 * precision / 20 + 1);
r12 = getRunner(11 * precision / 20 + 1, 12 * precision / 20 + 1);
r13 = getRunner(12 * precision / 20 + 1, 13 * precision / 20 + 1);
r14 = getRunner(13 * precision / 20 + 1, 14 * precision / 20 + 1);
r15 = getRunner(14 * precision / 20 + 1, 15 * precision / 20 + 1);
r16 = getRunner(15 * precision / 20 + 1, 16 * precision / 20 + 1);
Runnable r17 = getRunner(16 * precision / 20 + 1, 17 * precision / 20 + 1);
Runnable r18 = getRunner(17 * precision / 20 + 1, 18 * precision / 20 + 1);
Runnable r19 = getRunner(18 * precision / 20 + 1, 19 * precision / 20 + 1);
Runnable r20 = getRunner(19 * precision / 20 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
t4 = new Thread(r4);
t5 = new Thread(r5);
t6 = new Thread(r6);
t7 = new Thread(r7);
t8 = new Thread(r8);
t9 = new Thread(r9);
t10 = new Thread(r10);
t11 = new Thread(r11);
t12 = new Thread(r12);
t13 = new Thread(r13);
t14 = new Thread(r14);
t15 = new Thread(r15);
t16 = new Thread(r16);
Thread t17 = new Thread(r17);
Thread t18 = new Thread(r18);
Thread t19 = new Thread(r19);
Thread t20 = new Thread(r20);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
t9.start();
t10.start();
t11.start();
t12.start();
t13.start();
t14.start();
t15.start();
t16.start();
t17.start();
t18.start();
t19.start();
t20.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
t8.join();
t9.join();
t10.join();
t11.join();
t12.join();
t13.join();
t14.join();
t15.join();
t16.join();
t17.join();
t18.join();
t19.join();
t20.join();
break;
case 24:
r1 = getRunner(1, precision / 24 + 1);
r2 = getRunner(precision / 24 + 1, 2 * precision / 24 + 1);
r3 = getRunner(2 * precision / 24 + 1, 3 * precision / 24 + 1);
r4 = getRunner(3 * precision / 24 + 1, 4 * precision / 24 + 1);
r5 = getRunner(4 * precision / 24 + 1, 5 * precision / 24 + 1);
r6 = getRunner(5 * precision / 24 + 1, 6 * precision / 24 + 1);
r7 = getRunner(6 * precision / 24 + 1, 7 * precision / 24 + 1);
r8 = getRunner(7 * precision / 24 + 1, 8 * precision / 24 + 1);
r9 = getRunner(8 * precision / 24 + 1, 9 * precision / 24 + 1);
r10 = getRunner(9 * precision / 24 + 1, 10 * precision / 24 + 1);
r11 = getRunner(10 * precision / 24 + 1, 11 * precision / 24 + 1);
r12 = getRunner(11 * precision / 24 + 1, 12 * precision / 24 + 1);
r13 = getRunner(12 * precision / 24 + 1, 13 * precision / 24 + 1);
r14 = getRunner(13 * precision / 24 + 1, 14 * precision / 24 + 1);
r15 = getRunner(14 * precision / 24 + 1, 15 * precision / 24 + 1);
r16 = getRunner(15 * precision / 24 + 1, 16 * precision / 24 + 1);
r17 = getRunner(16 * precision / 24 + 1, 17 * precision / 24 + 1);
r18 = getRunner(17 * precision / 24 + 1, 18 * precision / 24 + 1);
r19 = getRunner(18 * precision / 24 + 1, 19 * precision / 24 + 1);
r20 = getRunner(19 * precision / 24 + 1, 20 * precision / 24 + 1);
Runnable r21 = getRunner(20 * precision / 24 + 1, 21 * precision / 24 + 1);
Runnable r22 = getRunner(21 * precision / 24 + 1, 22 * precision / 24 + 1);
Runnable r23 = getRunner(22 * precision / 24 + 1, 23 * precision / 24 + 1);
Runnable r24 = getRunner(23 * precision / 24 + 1, precision);
t1 = new Thread(r1);
t2 = new Thread(r2);
t3 = new Thread(r3);
t4 = new Thread(r4);
t5 = new Thread(r5);
t6 = new Thread(r6);
t7 = new Thread(r7);
t8 = new Thread(r8);
t9 = new Thread(r9);
t10 = new Thread(r10);
t11 = new Thread(r11);
t12 = new Thread(r12);
t13 = new Thread(r13);
t14 = new Thread(r14);
t15 = new Thread(r15);
t16 = new Thread(r16);
t17 = new Thread(r17);
t18 = new Thread(r18);
t19 = new Thread(r19);
t20 = new Thread(r20);
Thread t21 = new Thread(r21);
Thread t22 = new Thread(r22);
Thread t23 = new Thread(r23);
Thread t24 = new Thread(r24);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
t9.start();
t10.start();
t11.start();
t12.start();
t13.start();
t14.start();
t15.start();
t16.start();
t17.start();
t18.start();
t19.start();
t20.start();
t21.start();
t22.start();
t23.start();
t24.start();
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
t8.join();
t9.join();
t10.join();
t11.join();
t12.join();
t13.join();
t14.join();
t15.join();
t16.join();
t17.join();
t18.join();
t19.join();
t20.join();
t21.join();
t22.join();
t23.join();
t24.join();
break;
}
/* if (threadCount == 1) {
Runnable r1 = getRunner(1, precision);
Thread t1 = new Thread(r1);
t1.start();
t1.join();
}*/
/* Runnable r1 = getRunner(1, calculation + 1);
Runnable r2 = getRunner(calculation + 1, 2 * calculation + 1);
Runnable r3 = getRunner(2 * calculation + 1, 3 * calculation + 1);
Runnable r4 = getRunner(3 * calculation + 1, 4 * calculation);
Thread t1 = new Thread(r1);
t1.start();
Thread t2 = new Thread(r2);
t2.start();
Thread t3 = new Thread(r3);
t3.start();
Thread t4 = new Thread(r4);
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();*/
System.out.println("e = " + result);
long stop = System.currentTimeMillis();
long diff = stop - start1;
System.out.println("Time: " + diff + " ms");
System.out.println("Count of Threads: " + threadCount);
System.out.println("Precision: " + precision);
}
}
4 Answers 4
Which is faster, switch or for/while loop?
The speed difference for you here regarding a switch or a for/while loop is nothing compared to the rest of your code. You should really not be worried about that here.
That being said, I believe a switch is technically faster, but as I said. You shouldn't worry about that there!
You should be worried about maintainability, flexibility and readability. In which case a for-loop is substantively better.
Unexpected Results without Error Messages
Imagine the user currently inputting "10" as the number of threads. Then what happens? E becomes 1. No error message. This can be very confusing for a user (Based on a true story). Your current switch
approach does not support that option.
To fix this, either a) Add a default
statement to your switch
, stating that the chosen number of threads is not a valid option. b) Add support for it by using a for-loop instead!
Get rid of the static
habit!
Instead of getting used to static
, create an instance of your class and pass the required variables to it's constructor (such as precision
and threadCount
) and then use a non-static method to make the computations.
I think that the reason you're using static is that it's the "easiest/fastest" approach. But I'm warning you: It might come around and haunt you. I recommend avoiding over-using static.
By using the non-static approach and passing arguments to the constructor, you can mark several fields as final which is considered a good practice when possible.
Unused variables
static int numberOfThread = 4;
int calculation = precision / threadCount;
These variables does not seem to be used. Remove them.
Other comments
- Use
BigDecimal.ONE
instead ofnew BigDecimal("1")
- Instead of computing time with
System.currentTimeMillis();
useSystem.nanoTime();
- Create and return on same line. Instead of
Runnable runner = new Runnable...
you canreturn new Runnable...
- You have some commented code without explaining why it is commented. Remove that code next time before posting it for review to reduce confusion.
Once again though, most importantly:
Don't use switch
here, use for
!
You should write out your code so that what you are trying to do is clear. In this case, there are a number of distinct steps
- Create a bunch of Runnable
- Start them all
- Wait until they have all finished
- Report the result
For part #1 -- you commented out Runnable[]
but that was close to the right idea. I would instead recommend a List
List<Runnable> tasks = new ArrayList();
for (int i = 0; i < threadCount; ++i) {
int low = 1 + (i * precision / threadCount);
int high = 1 + ((i+1) * precision / threadCount);
tasks.add( getRunner(low,high) ) ;
}
For part #2 -- create an instance of an ExecutorService
, and submit all of the tasks to it. There are a number of different ExecutorService implementations, with different strategies to determine how they are run. Your implementation suggests that you want everything on a thread of its own, so perhaps
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
for(Runnable task : tasks) {
executor.submit(task);
}
For part #3, you can signal to the executor service that all tasks have been submitted, and then wait until they all finish.
// let the service know that all tasks are submitted
executor.shutdown();
executor.awaitTermination(...);
You're likely to have contention on the addResult()
method, because all of the worker threads need to block waiting for each other to do that part of the calculation. You might get a small improvement by writing the intermediate results to a thread safe queue, and adding another task that reads the events out of that queue to do the addition.
There are data structures, like a ring buffer, that can handle the thread contention more easily. Take a look at Disruptor, which is a library specifically designed for many threads writing data to one single consuming thread.
-
\$\begingroup\$ Is it normal for precision = 10000 and 1 thread that the program never gets build? \$\endgroup\$Didi– Didi2014年06月10日 18:14:09 +00:00Commented Jun 10, 2014 at 18:14
Your I/O is eccentric.
args[0]
, args[2]
, and args[4]
are ignored. args[5]
is also required, but the program never does anything with it.
Code in main()
should be kept to a minimum — just enough to process the arguments. There should be another method, such as public static BigDecimal e(int precision, int threads)
that does the "real" work, so that your class can be called by other code in the future.
Hard-coding result.txt
is user-unfriendly and limits the reusability of your code. I suggest printing your diagnostics to System.err
and the output to System.out
. Let the user redirect System.out
to a file using the shell, if desired. Your program shouldn't have to worry about such things.
The thread-spawning code really ought to be generalized. There should be an array of Thread
s rather than a large number of Thread
variables.
Calculating factorial()
from scratch is wasted work. You should be able to compute factorials based on factorials computed in previous terms.
Consider other algorithms for calculating e.
-
\$\begingroup\$ can you give me some idea how to rewrite factorial(),because i should use this kind of calculation .Thanks! \$\endgroup\$Didi– Didi2014年06月10日 18:12:18 +00:00Commented Jun 10, 2014 at 18:12
Be careful with MathContext
: you are creating a new object at each addition operation which could really lower your performance.
Here is another replacement for your switch statement using Java 8's Stream. I don't really recommend using this at the moment since it is very new and few Java programmers know about Streams. I also used some "functional" programming concepts from Java 8, so some part of the code might be completely incomprehensible if you are not used to that style of programming.
I am also using a CountDownLatch instead of all the join()
's. This feature has existed since Java 5. However, using Threads
and CountDownLatches
is kind of old fashioned and you should instead consider using Executor
s and such from the java.util.concurrent
packages.
MathContext mathContext = new MathContext(1000, RoundingMode.HALF_UP);
CountDownLatch countDownLatch = new CountDownLatch(nThreads);
IntStream.range(0, nThreads).forEach(i -> {
new Thread(() -> {
int startIndex = i * precision / nThreads + 1;
int endIndex = (i + 1) * precision / nThreads + 1;
if (i == nThreads - 1)
endIndex--;
Stream<BigDecimal> bigDecims = IntStream.range(startIndex, endIndex)
.mapToObj(j -> BigDecimal.valueOf(3 * 3 * j * j + 1).divide(factorial(3 * j)));
BigDecimal total = bigDecims
.reduce(BigDecimal.valueOf(0), (x, y) -> x.add(y, mathContext));
addResult(total);
countDownLatch.countDown();
}).start();
});
countDownLatch.await();
Explore related questions
See similar questions with these tags.