Multithreading in Python: A Reference

Python Methods and Functions

Multithreading in Python &this is a way to achieve multitasking in Python using the concept of threads.

 Multithreading python




What is a thread?

A thread &it is a component of any process controlled by the operating system. The OS provides concurrency or multitasking by dividing the process between threads. It is a lightweight process that provides a separate thread of execution.






What are the benefits of multithreading in Python?

There are many advantages to creating multithreaded applications. Let's take a look at some of the benefits:

  • Efficient use of resources;
  • More responsive;
  • Sharing resources makes it more economical;
  • Efficient use of multiprocessor architecture through parallelism;
  • Saves time;
  • Threads (since they are part of the same process) interact more easily with each other than if they were separate processes;
  • They do not require a lot of memory;
  • Multithreaded servers and interactive GUIs use multithreading exclusively.

Multithreading is used in cases:

  1. When the outputs of the subroutines need to be merged with the main program.
  2. If the main program contains a piece of code that is relatively independent of each other.
  3. When the outputs subroutines need to be combined with the main program.
  4. The main program contains a piece of code that is relative but independent of each other.

The Threading module defines many functions that are used to retrieve data associated with threads, and these functions are automatically executed.

threading.active_count ( )

This function returns the number of Thread objects that are currently alive. Here, the returned count is equal to the length of the list returned by enumerate ().

threading.current_thread ()

This function returns the current Thread object and it corresponds to the caller's thread of control.

threading.get_ident ()

This function returns the "thread id" of the current thread. This is a nonzero integer.

threading.enumerate ()

This function returns a list of all current Thread objects, including daemon threads, the current_thread () function creates a dummy thread and main thread and excludes terminated threads and threads that have not yet been started.

threading.main_thread ()

This function returns the main Thread object.

threading.settrace (Func)

When all threads are started from the thread module, set the trace function. Before calling the run () method, this function is passed to sys.settrace () for each thread.

threading.setprofile (FUNC)

When all threads are started from the threading module, set the profile function ... Before calling the run () method, this function is passed to sys.setprofile () for each thread. 

threading.stack_size ([size])



This function returns the size of the thread stack and is used when creating new threads.

 import threadin g def trace_function (): print ("Passing the trace function") def profile (): print ( "PROFILE THREAD:" + str (threading.current_thread (). GetName ())) class mythread (threading.Thread): def __init __ (self, thread_name, thread_ID): threading.Thread .__ init __ (self) self.thread_name = thread_name self.thread_ID = thread_ID def run (self): print (str (self.thread_ID)); print ("ACTIVE THREADS ARE:" + str (threading.active_count ())) print ("CURRENT THREAD IS:" + str (threading.current_thread (). getName ())) my_thread1 = mythread ( "PP", 500) my_thread2 = mythread ("PythonProgram", 1000); print ("NAME OF THE MAIN THREAD:" + str (threading.main_thread (). getName ())) print ("IDENTIFICATION OF MAIN THREAD:" + str (threading.get_ident ())) print ("STACK SIZE =" + str (threading.stack_size ())) print (threading.settrace (trace_function ())) threading.setprofile (profile ()) my_thread1.start () my_thread2.start () print ("LIST OF ENUMERATION:") print ( threading.enumerate ()) print ("EXIT") 

This constant has the maximum value allowed for the timeout parameter of lock functions (Lock.acquire (), RLock.acquire (), Condition.wait () etc.).

 NAME OF THE MAIN THREAD: MainThread IDENTIFICATION OF MAIN THREAD: 5436 STACK SIZE = 0 Passing the trace function None PROFILE THREAD: MainThread 500 1000LIST OF ENUMERATION: ACTIVE THREADS ARE: 6 [& lt; _MainThread (MainThread, started 5436) & gt ;, & lt; Thread (Thread-4, started daemon 1960) & gt ;, & lt; Heartbeat (Thread-5, started daemon 6452) & gt ;, & lt; HistorySavingThread (IPythonH istorySavingThread, started 4304) & gt ;, & lt; mythread (Thread-8, started 8460) & gt ;, & lt; mythread (Thread-9, started 4668) & gt;] EXIT CURRENT THREAD IS: Thread-8 ACTIVE THREADS ARE: 5 CURRE NT THREAD IS: Thread-9 

Let's move on to creating our first multi-threaded application.




1. Import the threading module.

We will use the threading module to create the thread.

 import threading 

The threading transmission module consists of a Thread class that is created to create a thread.

A thread can be created by creating an object of the class Thread. The arguments for this class are as follows:

  1. target: This specifies the function to be invoked by the thread. This function is a callable object called by the run () method of the stream.
  2. args: This is where we specify the target arguments of the function.
  3.  def print_hi (num): print ("Hi, you are customer", num) t1 = threading.Thread (target = print_square, args = ( 10,)) 

    The above code snippet calls a print_hi () called as a target parameter. This function has one parameter, namely num , which is specified using args .

    Illustration of the Main Stream and Children


    2. Start

    A thread is started by calling the start () method of the threading module passing a Thread object.

     t1.start () 

    It must be called at most once for each stream object. It organizes the call to the run () method of an object in a separate control thread.

    This method will raise a RuntimeError if called more than once on the same object thread.

    A thread is called in a program, which is itself a process. Thus, while the thread is running, the main program continues its execution as well.

    Therefore, we can suspend the main program (executed by the main thread) until the created thread finishes.




    3. Thread connection method

     def print_hi (num): print ("Hi, you are customer", num) t1 = threading.Thread (target = print_hi, args = (10,)) t1.start () t1.join () print ("End") 

    The above snippet uses the Thread class to create an object. assigned the name t1. The start () method is called on the t1 thread object that marks the start of thread activity.

    The join () method is then called. In this way, we ensure that the main program stops the execution of the main thread and waits for the end of thread t1. As soon as t1 completes its work, the main thread (main program) can continue its execution. Therefore, the print ("End") lines print ("End") are executed only after the thread has finished activity.

     Hi, you are customer 10 End 

    Without using the join () method, the interpreter has a choice between the two print statements & print ("Hi, you are customer", num) and print ("End") . In such scenarios, it is impossible to predict which print statement will be displayed first, because the execution of those lines is up to the interpreter.




    4. Thread synchronization in Python

    Thread synchronization is defined as a mechanism to ensure that no two threads are executing a specific segment of a program that accesses shared resources. Such sections of the program are called critical.

    Make sure that two threads do not access this resource at the same time, as this can lead to a race condition.

    Race condition is defined as a scenario where two or more threads access a shared resource with write permission and try to modify data. Thus, the value of such variables becomes unpredictable.

    Therefore, we use locks in the program, which temporarily stop the execution of the program until the lock is released. This is to prevent two threads from accessing the same variable and causing conflicts.




    Disadvantages of multithreading

    • Increases program complexity;
    • Needs synchronization of shared resources (objects, data);
    • Difficult to debug unpredictable results;
    • Creating and synchronizing threads is CPU and memory intensive.

    Links

    https://docs.python.org/3/library/threading.html


    < br>



Tutorials