Search code examples
pythonpython-3.xmultithreadingpython-multithreading

Printing Vaules in a pattern using multi-threading in python


The goal is to print: Fibonacci No.: Square of Fibo: Prime No: Square of the Prime Number: in a pattern upto first 10 vaules using multi threading .
Here is my code:

import threading
import time

def FibonacciNumbers(n):
    f1 = 0
    f2 = 1
    if (n < 1):
        return
    for x in range(0, n):
        print("Fibonacci No.: ")
        print(f2)
        time.sleep(1)
        next = f1 + f2
        f1 = f2
        f2 = next

def FibonacciSq(n):
    f1 = 0
    f2 = 1
    if (n < 1):
        return
    for x in range(0, n):
        print("Square of Fibo: ")
        print(f2*f2)
        time.sleep(1)
        next = f1 + f2
        f1 = f2
        f2 = next

def prime(x):
    i=1
    counter = 0
    while True:
        c=0;
        for j in range (1, (i+1), 1):
            a = i%j
            if (a==0):
                c = c+1
        if (c==2):
            print("Prime No: ")
            print (i)
            time.sleep(1)
            counter = counter + 1
            if counter >= x:
                break
        i=i+1

def primeSq(x):
    i=1
    counter = 0
    while True:
        c=0;
        for j in range (1, (i+1), 1):
            a = i%j
            if (a==0):
                c = c+1
        if (c==2):
            print("Square of the Prime Number: ")
            print (i*i)
            time.sleep(1)
            counter = counter + 1
            if counter >= x:
                break
        i=i+1


if __name__ == "__main__":
    t1 = threading.Thread(target=FibonacciNumbers, args=(10,))
    t2 = threading.Thread(target=FibonacciSq, args=(10,))
    t3 = threading.Thread(target=prime, args=(10,))
    t4 = threading.Thread(target=primeSq, args=(10,))
    t1.start()
    time.sleep(1)
    # t1.join()

    t2.start()
    time.sleep(1)
    # t2.join()

    t3.start()
    time.sleep(1)
    # t3.join()

    t4.start()
    time.sleep(1)
    # t4.join()
    t1.join()
    t2.join()
    t3.join()
    t4.join()

    print("Done!")

The out put I got from it is:

The output is generated in a random manner. I think it is due to some collision in the time when the result is generating . Can't figure out how to pause one thread until the next is finshed. Please help me to fix the output.

Fibonacci No.:
1
Fibonacci No.:
1
Square of Fibo:
1
Fibonacci No.:
2
Square of Fibo:
1
Prime No:
2
34
Square of Fibo:
169
441
Prime No:
Square of the Prime Number:
289
Fibonacci No.:
19
55
Square of Fibo:
1156
Square of Fibo:
Square of the Prime Number:
361
3025
Prime No:
23
Square of the Prime Number:
529
Prime No:
29
Square of the Prime Number:
841
Done!

Solution

  • When multiple threads concurrently access a single resource (in this case: the standard output), you need to somehow synchronise access (meaning: make all except one thread wait until the resource is free to use again).

    There are several solutions for this depending on the exact use-case. The most general solution is to use a lock. This requires two changes:

    1. Declare a global lock at the start of your file:

      lock = threading.Lock()
      
    2. Inside each function, wrap both print statements inside a locked block, e.g.:

      with lock:
          print("Fibonacci No.: ")
          print(f2)
      

    Note that locking in this fashion is quite an inefficient operation! If the aim of using concurrency was performance, this solution might well completely defeat the purpose. Writing efficient multi-threaded code is rarely trivial, and efficient synchronisation in particular requires a lot of though. (There are added complications because the most common Python’s implementations use a global interpreter lock, which implies that execution for the most part doesn’t really happen in parallel anyway.)

    The easiest practical, efficient solution in most cases is to avoid sharing resources between threads. In your case, this would mean not writing any output (functions that write output are generally suspect anyway): let each function generate results and collect them inside a list, or yield them as a generator. Then you can generate results in parallel, and print them sequentially afterwards (doing so requires a change though, since threading does not easily support functions that return values; however, the module concurrent.futures does).