Search code examples
python-3.xmultithreadingpython-multithreading

I want to run multiple threads in python after I input anthing from the keyboard and I am getting this error - Exception in thread Thread-4:


I want to run multiple threads in python after I input anthing from the keyboard and I am getting this error - Exception in thread Thread-4:

import threading
import os
import cv2

def task():
    user_input = input()
    print(user_input)
    print("Task assigned to thread: {}".format(threading.current_thread().name))
    print("ID of process running task : {}".format(os.getpid()))
    print("Thread started now")

if __name__ == "__main__":
    for i in range(1, 5):
         # Instantiates the thread
        t = threading.Thread(target=task, args=(i,))
        t.start()
        t.join()

Solution

  • You should post the whole traceback. Here is what I get in all 4 threads:

    Exception in thread Thread-1:
    Traceback (most recent call last):
      File "C:\Python38\lib\threading.py", line 932, in _bootstrap_inner
        self.run()
      File "C:Python38\lib\threading.py", line 870, in run
        self._target(*self._args, **self._kwargs)
    TypeError: task() takes 0 positional arguments but 1 was given
    

    It says the function task() was passed an argument when it didn't require any, so don't pass an argument when creating the thread:

    t = threading.Thread(target=task, args=())
    

    or make task() take an argument:

    def task(i):
    

    Asking for input in the thread doesn't really make sense either. No prompting and you won't know which thread is taking input.

    Since using threading and not multiprocessing module, os.getpid() is going to return the same value in all threads.

    Also, if you start and join the thread in the same loop, you aren't getting any parallelism. Start all the threads in one loop, then join (wait for completion) in another loop.

    Here's a solution that demonstrates parallelism:

    import threading
    import os
    import time
    
    def task(i):
        print(f'Task#{i} started in {threading.current_thread().name}')
        time.sleep(5) # do some "work"
        print(f'Task#{i} done')
    
    threads = [threading.Thread(target=task,args=(i,)) for i in range(1,5)]
    print(f'Start: {time.ctime()}')
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    print(f'End:   {time.ctime()}')
    

    Output (note start and end times are 5 seconds apart):

    Start: Sat Feb 15 16:22:59 2020
    Task#1 started in Thread-1
    Task#2 started in Thread-2
    Task#3 started in Thread-3
    Task#4 started in Thread-4
    Task#1 done
    Task#2 done
    Task#4 done
    Task#3 done
    End:   Sat Feb 15 16:23:04 2020
    

    A final note: A process can only run Python code in one thread at a time due to CPython's global interpreter lock (GIL) implementation, so the threading module won't save time for Python-intensive work, but is useful when Python is waiting on I/O or calling into native C modules that release the GIL. The multiprocessing module can be used to create multiple Python processes that aren't limited by the GIL, but has longer process initialization time and arguments are passed through inter-process methods.

    import multiprocessing as mp
    import os
    import time
    
    def task(i):
        print(f'Task#{i} started in {mp.current_process().name}')
        time.sleep(5)
        print(f'Task#{i} done')
    
    if __name__ == '__main__':
        processes = [mp.Process(target=task,args=(i,)) for i in range(1,5)]
        print(f'Start: {time.ctime()}')
        for p in processes:
            p.start()
        for p in processes:
            p.join()
        print(f'End:   {time.ctime()}')
    

    Output:

    Start: Sat Feb 15 16:32:26 2020
    Task#4 started in Process-4
    Task#3 started in Process-3
    Task#1 started in Process-1
    Task#2 started in Process-2
    Task#1 done
    Task#4 done
    Task#3 done
    Task#2 done
    End:   Sat Feb 15 16:32:31 2020