Search code examples
pythonmultithreadingperformanceprimes

Use 2 Threads to calculate the nth prime number in Python


I am trying to make a Prime number calculator using Python. I managed to write a sequential version but I have to make it parallel.

Requirements:

  1. The prime numbers must be newly calculated by the functions instead of being looked up somewhere.

  2. Must have 2 threads contributing to the calculation

  3. The program should be as fast as possible


Now the code I have is:

import sys
import math 
import cProfile

def is_prime(num):
    for j in range(2,int(math.sqrt(num)+1)):
        if (num % j) == 0:
            return False
    return True

def prime(nth):
    """Return the nth prime number.
    >>> prime(3)
    The 3th prime number is: 5
    >>> prime(4)
    The 4th prime number is: 7
    >>> prime(1000)
    The 1000th prime number is: 7919
    """
    i = 0
    num = 2

    while i < nth:
        if is_prime(num): 
            i += 1
            if i == nth:
                print('The ' + str(nth) + 'th prime number is: ' + str(num))
        num += 1

if __name__ == "__main__":
    import doctest
    doctest.testmod()
    cProfile.run('print(prime(1000))')

Solution

  • This is the answer I have currently,

    import threading, doctest, cProfile, time, random
    result = [2]
    counter = 1
    
    def get_int(num):
        for i in range(3, num):
            yield i
    
    def is_prime(num):
        for j in range(2,int(num)):
            if (num % j) == 0:
                return False
        result.append(num)
        return True 
    
    def prime_calculator(nth):
        lock = threading.Lock()
        global result, counter, integer
        while counter < (nth):
            if is_prime(next(integer)):
                lock.acquire()
                try:
                    counter += 1
                finally:
                    lock.release()
            time.sleep(random.random()/1000)
    
    def prime(nth):
        """Returns the nth prime number
        >>> prime(1)
        2
        >>> prime(2)
        3
        >>> prime(4)
        7
        >>> prime(1000)
        7919
        """   
        global integer, counter, result
        integer = get_int(99999999)
        threads = [threading.Thread(daemon=True, target=prime_calculator, args=(nth,)) for i in range(2)]
        [thread.start() for thread in threads]
        [thread.join() for thread in threads]
        counter = 1
        return result[-1]
    
    if __name__ == "__main__":
        doctest.testmod()
        cProfile.run('print(prime(1000))')
    

    However it is not thread-safe as it uses a counter, Will try to do one without counter later.