Search code examples
pythonpython-3.xmultithreadingqueuepython-multiprocessing

Using Queue in Multi-Threading returns address of function


I am trying to implement a multi-threading program which finds out prime numbers over multiple threads and aggregates their result.

I am using a queue to actually store the returned values. but when I print the values of queue only the address of the function is printed

n = int(input("Enter the value:"))

def task1():
    global n 
    print("Task 1 assigned to thread: {}".format(threading.current_thread().name)) 
    print("ID of process running task 1: {}".format(os.getpid()))
    a=[] 
    for i in range(2,n//2):
        c=0
        for j in range(2,i+1):
            if(i%j==0):
                c+=1
        if(c<=1):
            a.append(i)
    return a
    
    

def task2():
    global n
    print("Task 2 assigned to thread: {}".format(threading.current_thread().name)) 
    print("ID of process running task 2: {}".format(os.getpid())) 
    a=[] 
    for i in range(n//2+1,n):
        c=0
        for j in range(2,i+1):
            if(i%j==0):
                c+=1
        if(c<=1):
            a.append(i)
    return a
        
import queue
que=queue.Queue()
t1 = threading.Thread(target=lambda q: q.put(task1), args=(que,), name='t1') 
t2 = threading.Thread(target=lambda q: q.put(task2), args=(que,), name='t2') 

  # starting threads Spawn
t1.start() 
t2.start() 

  # wait until all threads finish Sync
t1.join() 
t2.join()

while not que.empty():
    result=que.get()
    print(result)

after running the code, this is the value I am getting

<function task1 at 0x00000204A9A11438>
<function task2 at 0x00000204A9A11288>

I need to print the array of prime numbers instead of the address.


Solution

  • target is the function to run in the thread. What you've made the thread do (and only do) is add a function reference to the queue. Your task are not run.

    Fixes:

    1. Set the task functions to each target.
    2. Since threads run in the same process, the queue can be accessed without passing it as a parameter. Same with the lock below.
    3. Write the results to the queue.
    4. global n isn't needed. It's only needed if you want to reassign n.
    5. Create a lock to manage printing if you will print in threads. It can get mixed up otherwise.
    6. Add appropriate imports (why do questioners always leave off the imports???)

    You'll also find that this likely runs slower than simply computing primes in one non-parallel task. Python processes are restricted by the global interpreter lock (GIL) to run Python code in only one thread at a time, so the threads are serialized if they run CPU-bound work, which this is.

    Threads are ideal for parallelizing I/O bound work. Use processes via the multiprocessing module to run CPU-bound tasks, but note that the overhead of creating processes and the inter-process communication to send parameters and results back to the main process can overwhelm simple CPU-bound operations like this, unless they run for a significant period of time.

    import threading
    import os
    import queue
    
    n = int(input("Enter the value:"))
    
    lock = threading.Lock()
    que = queue.Queue()
    
    def task1():
        with lock:
            print("Task 1 assigned to thread: {}".format(threading.current_thread().name)) 
            print("ID of process running task 1: {}".format(os.getpid()))
        a=[] 
        for i in range(2,n//2):
            c=0
            for j in range(2,i+1):
                if(i%j==0):
                    c+=1
            if(c<=1):
                a.append(i)
        que.put(a)
        
    def task2():
        with lock:
            print("Task 2 assigned to thread: {}".format(threading.current_thread().name)) 
            print("ID of process running task 2: {}".format(os.getpid())) 
        a=[] 
        for i in range(n//2+1,n):
            c=0
            for j in range(2,i+1):
                if(i%j==0):
                    c+=1
            if(c<=1):
                a.append(i)
        que.put(a)
            
    t1 = threading.Thread(target=task1, name='t1') 
    t2 = threading.Thread(target=task2, name='t2') 
    
      # starting threads Spawn
    t1.start() 
    t2.start() 
    
      # wait until all threads finish Sync
    t1.join() 
    t2.join()
    
    while not que.empty():
        result=que.get()
        print(result)
    

    Output:

    Enter the value: 100
    Task 1 assigned to thread: t1
    ID of process running task 1: 3864
    Task 2 assigned to thread: t2
    ID of process running task 2: 3864
    [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
    [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]