How To Use Python Threading Module For Multiple Threading

Python provides support for multi-threading through the _thread and threading modules. The threading module combines the existing functions of the _thread module and extends some new functions with a very rich thread operation function. This article mainly introduces the use of the threading module of Python multithreading.

1. Create Thread.

There are usually two methods to create threads using the threading module.

1.1 Use threading.Thread Class Constructor.

  1. Use the constructor of the Thread class in the threading module to create a thread, that is, directly instantiate the threading.Thread class, and call the start method of the instantiated object to create the thread.
  2. The constructor of the threading.Thread class.
    threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
    
    group:Specify the thread group to which the thread belongs. This parameter has not yet been implemented, and is reserved for future expansion of the ThreadGroup class implementation.
    
    target:The callable object used to call the run() method. The default is None, which means that no method needs to be called.
    
    args:The parameter tuple used to call the target function. The default is ().
    
    kwargs:The keyword-parameter dictionary used to call the target function. The default is {}.
    
    daemon:If daemon is not None, the thread will be explicitly set to daemon mode, regardless of whether the thread is in daemon mode or not. If it is None (the default value), the thread will inherit the daemon mode attributes of the current thread.
  3. In the following example, three instances of the Thread class are instantiated, and different parameters are passed to the work function. The start method starts the thread, and the join method blocks the main thread, waiting for the end of the current thread.
    import time
    import threading
    
    def work(num):
        print('Thread name:',threading.current_thread().getName(),'parameter:',num,'Start time:',time.strftime('%Y-%m-%d %H:%M:%S'))
    
    if __name__ == '__main__':
        print('Main thread start time:',time.strftime('%Y-%m-%d %H:%M:%S'))
        
        t1 = threading.Thread(target=work,args=(3,))
        t2 = threading.Thread(target=work,args=(2,))
        t3 = threading.Thread(target=work,args=(1,))
        
        t1.start()
        t2.start()
        t3.start()
        
        t1.join()
        t2.join()
        t3.join()
        
        print('Main thread end time:', time.strftime('%Y-%m-%d %H:%M:%S'))

1.2 Use threading.Thread Class Subclass.

  1. Inherit the Thread class in the threading module to create a sub-thread class, that is, use threading.Thread to derive a new subclass, instantiate the new class, and call its start method to create a thread.
  2. Creating a thread by inheritance includes the following steps.
  3. Define a subclass of the Thread class and override the run method of this class.
  4. Create an instance of the Thread subclass, that is, create a thread object.
  5. Call the start method of the thread object to start the thread.
  6. In the following example, the thread class MyThread is customized inherited from the threading.Thread class, and rewrite the __init__ method and run method.
    import time
    import threading
    
    class MyThread(threading.Thread):
        
        def __init__(self,num):
            super().__init__()
            self.num = num
        
        def run(self):
            print('Thread name:', threading.current_thread().getName(), 'parameter:', self.num, 'Start time', time.strftime('%Y-%m-%d %H:%M:%S'))
    
    if __name__ == '__main__':
       
        print('Main thread start time:',time.strftime('%Y-%m-%d %H:%M:%S'))
        
        t1 = MyThread(3)
        t2 = MyThread(2)
        t3 = MyThread(1)
       
        t1.start()
        t2.start()
        t3.start()
        
        t1.join()
        t2.join()
        t3.join()
        
        print('Main thread end time:', time.strftime('%Y-%m-%d %H:%M:%S'))

2. Daemon Thread.

  1. The daemon thread (also called background thread) runs in the background, and its task is to provide services for other threads.
  2. For example, the garbage collection thread of the Python interpreter is the daemon thread. If all foreground threads die, the daemon thread will die automatically.
  3. If you set a thread as a daemon thread, it means that this thread is not important. When the process exits, there is no need to wait for this thread to exit.
  4. If your main thread exits without the need to wait for the child threads to complete then set these child threads as daemon threads.
  5. If you want to wait for the child thread to complete before exiting, then do nothing, or explicitly set the child thread’s daemon attribute to false.
  6. The following example intuitively shows that the current thread ends, and the daemon thread will end automatically.
    # Do not set child thread as daemon thread explicitly
    import threading
    
    def work(num):
        for i in range(num):
            print(threading.current_thread().name + "  " + str(i))
    
    t = threading.Thread(target=work, args=(10,), name='daemon thread')
    t.start()
    
    for i in range(10):
        pass
    
    =========================================================================
    
    # Set child thread as daemon thread explicitly.
    import threading
    
    def work(num):
        for i in range(num):
            print(threading.current_thread().name + "  " + str(i))
    
    t = threading.Thread(target=work, args=(10,), name='daemon thread')
    t.daemon = True
    t.start()
    
    for i in range(10):
        pass
    

3. Thread Local Data.

  1. Python’s threading module provides the local method which returns a global object.
  2. Data stored by different threads using this object is not visible to other threads.
  3. Essentially, when different threads use this object, an independent dictionary is created for it.
  4. In the following example, num is a global variable and has become a public resource. By outputting the results, we find that the calculation results between the sub-threads interfere with each other.
    # Do not use threading.local
    import threading
    import time
    
    num = 0
    
    def work():
        global num
        
        for i in range(10):
            num += 1
            
        print(threading.current_thread().getName(), num)
        time.sleep(0.0001)
        
    for i in range(5):
        threading.Thread(target=work).start()
  5. In the below example using threading.local, num is a global variable, but the attribute num.x defined by each thread is unique to each thread, and this attribute is invisible to other threads, so the calculation results of each thread do not interfere with each other.
    # Use threading.local
    num = threading.local()
    
    def work():
        num.x = 0
        
        for i in range(10):
            num.x += 1
        
        print(threading.current_thread().getName(), num.x)
        time.sleep(0.0001)
    
    for i in range(5):
        threading.Thread(target=work).start()

4. Timer.

  1. The python threading module provides the Timer class to implement timer functions. Below is an example.
    # Execute only once use Timer class.
    from threading import Timer
    
    def work():
        print("Hello Python")
        
    # Execute the work method after 5 seconds
    t = Timer(5, work)
    t.start()
  2. A timer can only control the function to be executed once in the specified time. If we need to repeat the execution multiple times, we need to schedule. When we want to cancel the schedule, we can use the cancel method of Timer.
    # Repeat execution.
    count = 0
    
    def work():
        print('Current time:', time.strftime('%Y-%m-%d %H:%M:%S'))
        global t, count
        count += 1
        # If count is less than 5, start the next schedule
        if count < 5:
            t = Timer(1, work)
            t.start()
    
    # Specify the work method to execute after 2 seconds.
    t = Timer(2, work)
    t.start()

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.