'Multiprocessing in Python to find prime numbers
In Python 3 I have this assignment where I need to find prime numbers in a interval [a,b] using multiprocessing.
Let's take as an example the interval [0,30] and with the use of 3 processes I have three intervals [ai,bi] : [0.10] ,[10,20] , [20,30]
Here is my code:
import multiprocessing
import time
def isprime(num):
if num > 1:
for i in range(2, num):
if (num % i) != 0:
pass
else:
return num
if __name__ == "__main__":
pool = multiprocessing.Pool(3)
start_time = time.perf_counter()
result = pool.map(isprime, range(0,30))
finish_time = time.perf_counter()
print(f"Program finished in {finish_time-start_time} seconds")
print(result)
This is the outpot expected:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
This is what I get:
[None, None, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
Solution 1:[1]
You have three problems:
- Your
isprimefunction will implicitly returnNonefor arguments <= 1 but otherwise will always execute theelseclause of yourforstatement and return the passed argument. - On the assumption that
isprimewill return the passed argument if it is prime orNoneif it is not, then you need to filter outNonereturned values fromisprime. - You didn't actually solve the problem by breaking up the interval into ranges as you indicated was going to be your approach. I will address this in my comments following the code.
import multiprocessing
import time
def isprime(num):
if num < 2:
return None
for i in range(2, num):
if (num % i) == 0:
return None
else:
return num
if __name__ == "__main__":
pool = multiprocessing.Pool(3)
start_time = time.perf_counter()
result = list(filter(lambda x: x is not None, pool.map(isprime, range(0,30))))
finish_time = time.perf_counter()
print(f"Program finished in {finish_time-start_time} seconds")
print(result)
Prints:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
General Comments
Your isprime function could be greatly improved (do a Google for a better implementations). For example:
def isprime(num):
from math import sqrt, floor
if num < 2: return None
if num == 2: return num
if num % 2 == 0: return None
for d in range(3, floor(sqrt(num)) + 1, 2):
if num % d == 0: return None
return num
But as you see, as the argument n increases the more iterations of the main loop are required to prove that the passed argument is prime.
The way you could handle this problem is to implement some version of the Sieve of Eraosthenes algorithm, which is efficient in producing a series of prime numbers and you would then pass to this function a range of numbers between which the sieve function would return all the primes it found within that range. You would, of course, break up your initial range(0, 30) into a list of 3 subranges, i.e. [range(0, 10), range(10, 20), range(20, 30)], which would be passed to your map method.
But even the standard Sieve algorithm must start generating primes starting with 2 so even when you pass the argument range(10, 20) to it, the function would have to duplicate work that is being done when the argument range(0, 10) is being passed.
So using multiple calls to a isprime method is not efficient for finding a range of primes but a Sieve algorithm gains nothing from a multiprocessing implementation (multiprocessing actually hurts performance). The best way to solve this problem would be with a non-multiprocessing Sieve.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
