If we were to run the last program, we'll see that both the process pools iterate through every element in the array, printing out whether or not each value is prime or not before printing out the total time for execution.
This is followed, immediately, by the thread pool executor, which follows exactly the same process of calculating the prime before printing out the total execution time. You should see an output that is similar to this on your terminal:
$ python3.6 08_poolImprovement.py
112272535095293 is prime: True
...
1099726899285419 is prime: False
2.8411907070549205 Seconds Needed for ProcessPoolExecutor
112272535095293 is prime: True
...
1099726899285419 is prime: False
4.426182378898375 Seconds Needed for ThreadPoolExecutor
ProcessPoolExecutor in this case, managed to work through the list in approximately 2.8 seconds, while the total time needed for ThreadPoolExecutor was 4.4 seconds. This represents an almost 60% increase in the total processing time for utilizing threads.
If we tried to do this in a single-threaded manner, we would see that the time taken for the program to run through our array of values would be slightly faster than the execution time for our ThreadPoolExecutor. If you wish to test this yourself, then you can add the following code to the bottom of the main function in the previous example:
t3 = timeit.default_timer()
for number in PRIMES:
isPrime = is_prime(number)
print("{} is prime: {}".format(number, isPrime))
print("{} Seconds needed for single threaded execution".format(timeit.default_timer()-t3))