I got a task to filter a list (vector) from words for a prefix. The algorithm is supposed to use modern multi-core processors.
the solution have is to use many threads to handle the list.
// PrintWriter writer = new PrintWriter("C:\\DemoList.txt", "UTF-8");
//
// for(char i = 'A'; i<= 'Z'; i++) {
// for(char j = 'A'; j<= 'Z'; j++) {
// for(char n = 'A'; n<= 'Z'; n++) {
// for(char m = 'A'; m<= 'Z'; m++) {
// writer.println("" + i + j + n + m );
// }
//
// }
// }
// }
List<String> allLines = Files.readAllLines(Paths.get("C:\\", "DemoList.txt"));
Collections.shuffle(allLines);
String pattern = "AA";
List<String> result = new ArrayList<>();
int cores = Runtime.getRuntime().availableProcessors();
int threadsNum = allLines.size() / cores;
long start_time = System.nanoTime();
for (String word : allLines) {
if (word.startsWith(pattern))
result.add(word);
}
long end_time = System.nanoTime();
double difference = (end_time - start_time) / 1e6;
System.out.println("Time difference in Milliseconds with Brute-Force: " + difference);
//With Parallisim:
long new_start_time = System.nanoTime();
List<String> filteredList = allLines.parallelStream().filter(s -> s.startsWith(pattern))
.collect(Collectors.toList());
long new_end_time = System.nanoTime();
double new_difference = (new_end_time - new_start_time) / 1e6;
System.out.println("Time difference in Milliseconds with Stream from Java 8: " + new_difference);
Result: Time difference in Milliseconds with Brute-Force: 33.033602 Time difference in Milliseconds with Stream from Java 8: 65.017069
Each thread should filter a range from the list.
Do you have a better idea? Do you think, that i should sort the original list and than doing binary search on it? should i use multi-threading also in the binary sort, or shall i use the Collections.sort? How would you implement that?
From your code sample, your method of time measurement borders on Micro Benchmarking, for which simply measuring time for a single execution is misleading.
You can see it discussed at length in the following StackOverflow post: How do I write a correct micro-benchmark in Java?
I've written a more accurate benchmark to obtain a more precise measurment of your sample code. The code has run on a QuadCore i7 with multithreading (but it's a laptop, due to power and heat management, results may be slightly biased against multithreaded code that produces more heat).
Here are the results
So the sequential version looks way faster up to a few thousand elements, they are on par with manual threading a bit before 10k, and with parallel stream a bit after, and threaded code performs better from there on.
Considering the amount of code needed to write the "manual threading variant", and the risk of creating a bug there or an inefficiency by badling calculating batch size, I'd probably not elect that option even if it looks like it can be faster than streams for huge lists.
I would not try to sort first, then binary search as filtering is a O(N) operation, and sorting a O(Nlog(N)) (on top of which you have to add a binary search). So unless you have a very precise pattern on the data I do not see it working at your advantage.
Be aware though not to draw conclusion this benchmark can not support. For one thing, it is based on the assumption that the filtering is the only thing happening in the program and fighting for CPU time. If you are in any kind "multi-user" application (e.g. web application), then this is probably not true, and you may very well lose everything you though you would gain by multithreading.
Since Java 8, you can use streams to solve the problem in a few lines:
I suggest you this reading and to look at this question to understand if parallelism will help you or not.