Parallel Word Count per Line
Problem
Each input line is a task. Count the words of every line in parallel with a pool of worker threads (ExecutorService in Java, ThreadPoolExecutor in Python; JavaScript has one thread, so its version only shows the same result with map). Print the counts in the original line order, one per line, not in the order in which the tasks finish.
Constraints
- 1 <= lines <= 1000
Examples
Input
hello world a b c d single
Output
2 4 1
Solutions
The results are read in submission order, so the output is the same on every run, even though the tasks may finish in any order. The JavaScript version is concurrent (one thread, many promises), the Java and Python versions use real worker threads.
/*
* Problem : Word counts.
* Input : Lines of text.
* Output : One count per line.
* Approach: Worker pool.
* Time : O(total words)
* Space : O(n)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// This method solves the task. It receives the input and returns the answer.
static String[] solve(String[] lines) {
// Step 1: A fixed pool of 4 worker threads runs the tasks.
java.util.concurrent.ExecutorService pool = java.util.concurrent.Executors.newFixedThreadPool(4);
try {
// Step 2: Submit one task per line. Each task counts the words of its own line.
java.util.List<java.util.concurrent.Future<Integer>> futures = new java.util.ArrayList<>();
for (String line : lines) {
futures.add(pool.submit(() -> line.split(" ").length));
}
// Step 3: Read the futures in the order we created them. get() waits when a result is not ready.
String[] output = new String[lines.length];
for (int i = 0; i < futures.size(); i++) {
output[i] = String.valueOf(futures.get(i).get());
}
return output;
} catch (InterruptedException | java.util.concurrent.ExecutionException error) {
// Step 4: get() can fail. We turn the checked error into an unchecked one.
throw new IllegalStateException(error);
} finally {
// Step 5: Always shut the pool down, or the program may never end.
pool.shutdown();
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
java.util.List<String> all = new java.util.ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
all.add(line);
}
}
String[] lines = all.toArray(new String[0]);
System.out.println(String.join("\n", solve(lines)));
}
}
Hints (1)
- Why is the output order always the same?