In this article we will discuss how to create threads in python that will run a function (with or without arguments) in parallel to main thread.

Python provides a threading module to manage threads. To use that we need to import this module i.e.

import threading

Now Python’s threading module provides a Thread class to create and manage threads. Thread class provides a constructor in which we can pass a callable entity i.e. function or member function etc and arguments require by that function in args i.e.
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

For creating threads we can create objects of this Thread class by passing function which we want to run in separate thread. Each Thread class object represents a thread and we can control that thread by calling member function of this thread object.

Let’s create a thread using Thread class by passing a function with or without arguments.

Create a Thread with a function

Suppose we have a function that print 5 lines in a loop and sleeps for 1 second after printing every line i.e.

'''
This function will print 5 lines in a loop and sleeps for 1 second after
printing a line.
'''
def threadFunc():
   for i in range(5):
       print('Hello from new Thread ')
       time.sleep(1)

When called, this function will complete in around 5 seconds.

As our main function runs in main thread, we want to create a new thread that will execute threadFunc() in parallel to main thread.
For that new need to create a Thread class object and pass function name (which we want to execute in new thread) in target argument i.e.

# Create a Thread with a function without any arguments
th = threading.Thread(target=threadFunc)

It will create Thread class object th that can run the function provided in target argument in parallel thread, but thread has not started yet. To start the thread we need to call the start() member function from thread object i.e.
# Start the thread
th.start()

# Print some messages on console
for i in range(5):
   print('Hi from Main Thread')
   time.sleep(1)

# Wait for thread to finish
th.join()

th.start() will start a new thread, which will execute the function threadFunc() in parallel to main thread. After calling start() function on thread object, control will come back to Main thread and new thread will execute in parallel to Main thread.

So, both main() function and threadFunc() will run in parallel and print logs in parallel for around 5 seconds. Therefore output of above code is,

Hello from new Thread 
Hi from Main Thread
Hello from new Thread 
Hi from Main Thread
Hi from Main Thread
Hello from new Thread 
Hello from new Thread 
Hi from Main Thread
Hi from Main Thread
Hello from new Thread

In the end main thread will wait for thread th to exit by calling join() function on the thread object. This call is blocking until thread pointed by object exits.

Why main thread called the join() ?

If we haven’t called the join() function in main thread, then main() function will not wait for thread pointed by th to finish. So, if main() function finishes it’s work first, it can exit without for other thread to finish. Therefore calling join() on thread object will reduce the bugs.

Complete example is as follows,

import threading
import time

'''
This function will print 5 lines in a loop and sleeps for 1 second after
printing a line.
'''
def threadFunc():
    for i in range(5):
        print('Hello from new Thread ')
        time.sleep(1)


def main():

    print('**** Create a Thread with a function without any arguments ****')

    # Create a Thread with a function without any arguments
    th = threading.Thread(target=threadFunc)

    # Start the thread
    th.start()

    # Print some messages on console
    for i in range(5):
       print('Hi from Main Thread')
       time.sleep(1)

    # Wait for thread to finish
    th.join()

if __name__ == '__main__':
   main()

Output:
**** Create a Thread with a function without any arguments ****
Hello from new Thread 
Hi from Main Thread
Hello from new Thread 
Hi from Main Thread
Hi from Main Thread
Hello from new Thread 
Hello from new Thread 
Hi from Main Thread
Hi from Main Thread
Hello from new Thread

Create a Thread from a function with arguments

What if we have a function that accepts few arguments i.e.

'''
A Dummy function that accepts 2 arguments i.e. Filename and encryption type
and sleeps for 5 seconds in a loop while printing few lines.
This is to simulate a heavey function that takes 10 seconds to complete
'''
def loadContents(fileName, encryptionType):
    print('Started loading contents from file : ', fileName)
    print('Encryption Type : ', encryptionType)
    for i in range(5):
       print('Loading ... ')
       time.sleep(1)
    print('Finished loading contents from file : ', fileName)

This function is a simulation of a heavy function that accepts two arguments i.e. filename and encryption type, then does some stuff that takes around 5 seconds.
Now to create a thread object that runs this function in parallel thread, we need to pass the function arguments as tuple in args argument of the Thread class constructor i.e.
# Create a thread from a function with arguments
th = threading.Thread(target=loadContents, args=('users.csv','ABC' ))

# Start the thread
th.start()

# print some lines in main thread
for i in range(5):
    print('Hi from Main Function')
    time.sleep(1)

# Wait for thread to finish
th.join()

It will create a thread object that can run the passed function in new thread in parallel to main thread. Both the main() function and loadContents() will run in parallel and both will print logs in parallel. Therefore output of the above code is ,
Started loading contents from file :  users.csv 
Hi from Main Function
Encryption Type :  ABC
Loading ... 
Hi from Main Function
Loading ... 
Hi from Main Function
Loading ... 
Hi from Main Function
Loading ... 
Hi from Main Function
Loading ... 
Finished loading contents from file :  users.csv

Another Important Point is if we have a function that accepts a single argument then we need to pass the tuple in args argument with extra comma like this,
th = threading.Thread(target=someFunction, args=('sample' , ))

Complete example is as follows,
import threading
import time

'''
A Dummy function that accepts 2 arguments i.e. Filename and encryption type
and sleeps for 5 seconds in a loop while printing few lines.
This is to simulate a heavey function that takes 10 seconds to complete
'''
def loadContents(fileName, encryptionType):
    print('Started loading contents from file : ', fileName)
    print('Encryption Type : ', encryptionType)
    for i in range(5):
       print('Loading ... ')
       time.sleep(1)
    print('Finished loading contents from file : ', fileName)


def main():

    print('**** Create a Thread with a function with arguments ****')

    # Create a thread from a function with arguments
    th = threading.Thread(target=loadContents, args=('users.csv','ABC' ))

    # Start the thread
    th.start()

    # print some lines in main thread
    for i in range(5):
        print('Hi from Main Function')
        time.sleep(1)

    # Wait for thread to finish
    th.join()

if __name__ == '__main__':
   main()

Output:
**** Create a Thread with a function with arguments ****
Started loading contents from file : Hi from Main Function
 users.csv
Encryption Type :  ABC
Loading ... 
Hi from Main Function
Loading ... 
Hi from Main Function
Loading ... 
Hi from Main Function
Loading ... 
Hi from Main Function
Loading ... 
Finished loading contents from file :  users.csv


Important Point about Outputs:
In above examples both main thread and our new thread are running in parallel and print messages on the console in parallel. Therefore order of outputs may vary from above outputs because console is a shared resource used by 2 threads in parallel. In future articles we will discuss how to synchronize a single resource between threads.

 

Join a list of 2000+ Programmers for latest Tips & Tutorials