1

I'm trying to compare single-threaded vs multi-threaded performance and coded a Prime Number checker.

It's just two functions, one running in normal single-thread mode, and the other uses the python concurrent module and tries to queue a bunch of processes to check whether a number is prime or not.

The thing is, it works way faster in single-thread mode than multi-thread mode.

Here is my code:

import time, os, math, threading
from concurrent import futures

N = 1000

pList = []
pListM = []

processes = []
ex = futures.ProcessPoolExecutor()

def isPrime(n):
    if n < 2:
        return (n,False)
    if n == 2:
        return (n,True)
    if n % 2 == 0:
        return (n,False)

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return (n,False)
    return (n,True)

def firstPrimes(n):
        initTime = time.perf_counter()
        global pList
        i = 0
        while len(pList) < n:
                if isPrime(i): 
                        pList.append(i)
                i = i+1
        totalTime = time.perf_counter() - initTime
        print(pList)
        print("Single-Threaded it took ",totalTime," seconds to find the first ",N," primes.")

def done(fn):
    global N
    if fn.cancelled():
        print('{}: canceled'.format(fn))
    elif fn.done():
        error = fn.exception()
        if error:
            print('{}: error returned: {}'.format(
                fn.arg, error))
        else:
            result = fn.result()
##            print("\nEl resultado fue ",result,"\n")
##            print("Will pop index: ", result[0])
            processes.remove([result[0],fn])
            if result[1] and len(pListM) < N:
                    pListM.append(result[0])
##                    print("La lista de primos es: ",pListM)


def firstPrimesM(n):
        initTime = time.perf_counter()
        global pListM
        global processes
        global ex
        i = 0

        while len(pListM) < n:
                if len(processes) < 16:
##                        print("submiting process ",i)
                        pro = ex.submit(isPrime, i)
                        pro.add_done_callback(done)
                        processes.append([i,pro])
##                        print(processes)
                        i = i + 1
        for i, pro in reversed(processes):
                if not pro.cancel():
                        print('did not cancel {}'.format(i))
        ex.shutdown()
        totalTime = time.perf_counter() - initTime
        print(pListM)
        print("Multi-Threaded it took ",totalTime," seconds to find the first ",N," primes.")

if __name__ == '__main__':
        try:
                firstPrimes(N)
                firstPrimesM(N)
        except KeyboardInterrupt:
            print("User exited with Ctrl + C")
            for i, pro in reversed(processes):
                if not pro.cancel():
                        print('did not cancel {}'.format(i))
            ex.shutdown()

Any help would be very appreciated!

Eros
  • 11
  • 2
  • This is likely because of synchronization/process startup overhead. In other words starting another process takes time,and in this case that time is greater than the time gained. – PiRocks Feb 17 '20 at 00:23
  • @PiRocks I checked the Task Manager in Windows and the processes were there but only 1 was doing something. – Eros Feb 17 '20 at 00:59
  • That is consistent with what I said. If the majority of the time is spent communicating with other threads that could manifest as no cpu time being spent in worker threads. – PiRocks Feb 17 '20 at 01:01
  • By python's definition of these terms you code is multi-process, not multi-threaded. – President James K. Polk Feb 18 '20 at 03:58
  • I observed the exact same behaviour when using scipy.linalg.eigsh with large sparse matrices, single thread execution of the code was about 3 times faster than multi-thread execution. – Alain Mar 22 '20 at 00:17

0 Answers0