The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 59 Python Parallelism and Concurrency - Parallelism and Concurrency and Threads and Processes
Abstracts:
In Python, parallelism and concurrency are commonly used to describe the way a program is executed, and thread and process are two common ways to implement parallelism and concurrency; a thread is the smallest unit of execution in a process, and multiple threads can share memory space in the same process; a process is an instance of a program being executed on a computer, and each process has its own memory space and resources; a process is an instance of a program being executed on a computer, and each process has its own memory space and resources. Thread is the smallest unit of execution in a process, and multiple threads can share the same process's memory space; process is an instance of a program being executed in a computer, and each process has its own memory space and resources.
Link to original article:
FreakStudio's Blog
Past Recommendations:
You're learning embedded and you don't know how to be object oriented?
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 00 Introduction to Object-Oriented Design Methods
The network's most suitable for the introduction of object-oriented programming tutorials: 01 Basic Concepts of Object-Oriented Programming
The Best Object-Oriented Programming Tutorials for Getting Started on the Web: 02 Python Implementations of Classes and Objects - Creating Classes with Python
The Best Object-Oriented Programming Tutorials for Getting Started on the Web: 03 Python Implementations of Classes and Objects - Adding Attributes to Custom Classes
The Best Object-Oriented Programming Tutorial on the Net for Getting Started: 04 Python Implementation of Classes and Objects - Adding Methods to Custom Classes
The Best Object-Oriented Programming Tutorial on the Net for Getting Started: 05 Python Implementation of Classes and Objects - PyCharm Code Tags
The best object-oriented programming tutorials on the net for getting started: 06 Python implementation of classes and objects - data encapsulation of custom classes
The best object-oriented programming tutorial on the net for getting started: 07 Python implementation of classes and objects - type annotations
The best object-oriented programming tutorials on the net for getting started: 08 Python implementations of classes and objects - @property decorator
The best object-oriented programming tutorials on the net for getting started: 09 Python implementation of classes and objects - the relationship between classes
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 10 Python Implementations of Classes and Objects - Class Inheritance and Richter's Replacement Principle
The best object-oriented programming tutorials on the web for getting started: 11 Python implementation of classes and objects - subclasses call parent class methods
The network's most suitable for the introduction of object-oriented programming tutorials: 12 classes and objects of the Python implementation - Python using the logging module to output the program running logs
The network's most suitable for the introduction of object-oriented programming tutorials: 13 classes and objects of the Python implementation - visual reading code artifacts Sourcetrail's installation use
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 14 Python Implementations of Classes and Objects - Static Methods and Class Methods for Classes
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 15 Python Implementations of Classes and Objects - __slots__ Magic Methods
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 16 Python Implementations of Classes and Objects - Polymorphism, Method Overriding, and the Principle of Open-Close
The Best Object-Oriented Programming Tutorials for Getting Started on the Web: 17 Python Implementations of Classes and Objects - Duck Types and "file-like objects"
The network's most suitable for the introduction of object-oriented programming tutorials: 18 classes and objects Python implementation - multiple inheritance and PyQtGraph serial port data plotting graphs
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 19 Python Implementations of Classes and Objects - Using PyCharm to Automatically Generate File Annotations and Function Annotations
The best object-oriented programming tutorials on the web for getting started: 20 Python implementation of classes and objects - Combinatorial relationship implementation and CSV file saving
The best introductory object-oriented programming tutorials on the net: 21 Python implementation of classes and objects - Organization of multiple files: modulemodule and packagepackage
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 22 Python Implementations of Classes and Objects - Exceptions and Syntax Errors
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 23 Python Implementation of Classes and Objects - Throwing Exceptions
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 24 Python Implementations of Classes and Objects - Exception Catching and Handling
The best object-oriented programming tutorials on the web for getting started: 25 Python implementation of classes and objects - Python to determine the type of input data
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 26 Python Implementations of Classes and Objects - Context Managers and with Statements
The best introductory object-oriented programming tutorials on the net: 27 Python implementation of classes and objects - Exception hierarchy and custom exception class implementation in Python
The best object-oriented programming tutorials on the net for getting started: 28 Python implementations of classes and objects - Python programming principles, philosophies and norms in a big summary
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 29 Python Implementations of Classes and Objects - Assertions and Defensive Programming and Use of the help Function
The Best Object-Oriented Programming Tutorials for Getting Started on the Web: 30 Python's Built-In Data Types - the root class of object
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 31 Python's Built-in Data Types - Object Object and Type Type
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 32 Python's Built-in Data Types - Class Class and Instance Instance
The Best Object-Oriented Programming Tutorials for Getting Started on the Web: 33 Python's Built-In Data Types - The Relationship Between the Object Object and the Type Type
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 34 Python's Built-In Data Types - Python's Common Compound Data Types: Tuples and Named Tuples
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 35 Python's Built-In Data Types - Document Strings and the __doc__ Attribute
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 36 Python's Built-In Data Types - Dictionaries
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 37 Python's Common Composite Data Types - Lists and List Derivatives
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 38 Python's Common Composite Data Types - Using Lists to Implement Stacks, Queues, and Double-Ended Queues
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 39 Python Common Composite Data Types - Collections
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 40 Python's Common Compound Data Types - Enumeration and Use of the enum Module
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 41 Python's Common Composite Data Types - Queues (FIFO, LIFO, Priority Queue, Double-Ended Queue, and Ring Queue)
The best introductory object-oriented programming tutorials on the web: 42 Python commonly used composite data types-collections container data type
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 43 Python's Common Composite Data Types - Extended Built-In Data Types
The Best Object-Oriented Programming Tutorial on the Net for Getting Started: 44 Python Built-In Functions and Magic Methods - Magic Methods for Rewriting Built-In Types
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 45 Python Implementations of Common Data Structures - Chain Tables, Trees, Hash Tables, Graphs, and Heaps
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 46 Python Function Methods and Interfaces - Functions and Event-Driven Frameworks
The network's most suitable for the introduction of object-oriented programming tutorials: 47 Python function methods and interfaces - callback function Callback
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 48 Python Function Methods and Interfaces - Positional Parameters, Default Parameters, Variable Parameters, and Keyword Parameters
Best Object-Oriented Programming Tutorials on the Net for Getting Started: 49 Python Functions Methods and Interfaces - Difference between Functions and Methods and lamda Anonymous Functions
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 50 Python Function Methods and Interfaces - Interfaces and Abstract Base Classes
The Best Object-Oriented Programming Tutorials on the Web for Getting Started: 51 Python Function Methods and Interfaces - Implementing Interfaces with Zope
Best Object-Oriented Programming Tutorials for Beginners on the Web: 52 Python Functions Methods and Interfaces-Protocol Protocols and Interfaces
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 53 Python Strings and Serialization - Strings and Character Encoding
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 54 Python Strings and Serialization - String Formatting and the format method
The Best Object-Oriented Programming Tutorial on the Net for Getting Started: 55 Python Strings and Serialization - Byte Sequence Types and Variable Byte Strings
The Best Object-Oriented Programming Tutorials on the Net for Getting Started: 56 Python Strings and Serialization - Regular Expressions and re Module Applications
The Best Object-Oriented Programming Tutorial on the Net for Getting Started: 57 Python Strings and Serialization - Serialization and Deserialization
The Best Object-Oriented Programming Tutorial on the Net for Getting Started: 58 Python Strings and Serialization - Definition and Implementation of Serialized Web Objects
More highlights to watch:
Accelerating Your Python: A Quick Guide to Python Parallel Computing
Understanding CM3 MCU Debugging Principles in One Article
Liver half a month, embedded technology stack summary out of the big
The "Secrets of the Martial Arts" of the Computer Competition
A MicroPython open source project collection: awesome-micropython, including all aspects of Micropython tool library
Avnet ZUBoard 1CG Development Board - A New Choice for Deep Learning
SenseCraft Deploys Models to Grove Vision AI V2 Image Processing Module
Documentation and code acquisition:
The following link can be accessed to download the document:
/leezisheng/Doc
This document mainly introduces how to use Python for object-oriented programming, which requires readers to have a basic understanding of Python syntax and microcontroller development. Compared with other blogs or books that explain Python object-oriented programming, this document is more detailed and focuses on embedded host computer applications, with common serial port data sending and receiving, data processing, and dynamic graph drawing as application examples for the host computer and the lower computer, and using Sourcetrail code software to visualize and read the code for readers' easy understanding.
The link to get the relevant sample code is below:/leezisheng/Python-OOP-Demo
main body (of a book)
Basic concepts of parallelism and concurrency
In the above simulated sensor-host example, we can see that our program always executes sequentially, e.g., we use the serial port assistant to cooperate with the host MasterClass class, the host class sends commands, and we input the simulated data through the serial port assistant to send it to the host side, but we have never involved the interaction between the MasterClass host class and the SensorClass However, the interaction between the MasterClass host class and the SensorClass has never been involved, i.e., the instance of SensorClass receives commands from the instance of MasterClass, parses them, and then performs the specified operations.This is due to the fact that we have been using single-threaded sequential execution in our previous code, and the implementation of the ReadSerial serial port read method (() method) in SerialClass, the parent class of SensorClass and MasterClass, uses a blocking method, so that the SensorClass waits for commands or the MasterClass waits for data and must wait for the data to be received before executing the next operation. The next operation can be performed only after the data is received by the sensor class waiting for a command or the host class waiting for data.
If the MasterClass host class and the SensorClass sensor class are required to take turns working alternately/simultaneously, then you need to use multi-threading/multi-processing in Python to realize parallel/concurrent multi-tasking.
Concurrency refers to the ability of an application to execute different tasks alternatively, which means that a single processor needs to be allowed to switch between different tasks multiple times per second. Parallel means that multiple processors or multi-core processors handle several different tasks at the same time. The difference between the two is shown in the figure below:
Multitasking switching or processing can be done by multiple processes or by multiple threads within a single process.
Process (process) is the smallest unit of resource allocation, a program has at least one process, the process has its own independent address space, memory, data stack, etc., so the process occupies more resources. Because of the independent resources of the process, so the communication is not convenient, can only use the inter-process communication (IPC).
A thread is the smallest unit of program execution, and a process has at least one thread. Threads share data in the process, they use the same address space, the use of threads to create a fast, less overhead than the process. Threads under the same process share global variables, static variables and other data, so thread communication is very convenient, but there will be data synchronization and mutual exclusion problems, how to deal with synchronization and mutual exclusion is the difficulty of writing multi-threaded programs.
The relationship between the two is shown in the figure below:
Before explaining multithreading and multiprocessing, let's review some of the classes and interrelationships that have been implemented previously:
Among other things, the DateProcess data processing class has not yet been linked to the host class, which we will implement in the next code.
multi-threaded
The mechanism for running multiple threads is similar to starting and executing several different programs at the same time. Unlike processes, each independent process has an entry point to the program, a defined sequence of execution, and an exit point. Threads, however, cannot execute independently; they must rely on an application program to provide execution control.
Each thread has its own set of CPU registers, which are called the thread's context. The context reflects the state of the CPU registers at the time of the thread's last execution. The instruction pointer and stack pointer registers are particularly critical in a thread's context. Threads always run in the context of a process, and these addresses are used to identify memory locations in the address space of the process that owns the thread. In this way, threads can work together to achieve more efficient task processing.
Before we can use multithreading, we need to import the threading module from Python:
from threading import Thread
Creating and running multiple threads
There are two ways to use threads in Python, functions or wrapping thread objects in classes:
- Function method: Call the Thread function in the thread module to create a thread instance.
The syntax is as follows.
- Wrapping thread objects in classes: Create threads using the Threading module, inheriting directly from it and overriding the init and run methods.
Here, we implement multi-threaded running for the SensorClass sensor class, first make it inherit from Thread class, call the initialization method of Thread in the initialization method of SensorClass, and at the same time, create a new run() method, complete the initialization and turn on the sensor in the run() method, and then create a while loop, each time the In the run() method, the sensor is initialized and turned on, and then a while loop is created. Each time the loop generates a new data value (the analog collected sensor data) and performs the corresponding operation according to the received command. The example code is as follows:
class SensorClass(SerialClass,Thread).
'''
Sensor class, inherited from SerialClass\Thread
'''
... ...
_# Class initialization_
def __init__(self,port:str = "COM11",id:int = 0,state:int = WORK_MODE["RESPOND_MODE"])::
_# Determine if the input port number is the same as the input port number.
_# Determine if the input port number is of type str_.
if type(port) is not str.
raise TypeError("InvalidPortError:",port)
_# Determine if id number is between 0 and 99.
if id < 0 or id > 99.
_# When the exception is triggered, the code that follows will not be executed.
_# This exception is raised when an incorrect type of parameter is passed to a function or method or when the value of a parameter is not legal. _
raise InvalidIDError("InvalidIDError:",id)
_# Call the initialization method of the parent class, the super() function connects the parent class to the child class _
super(). __init__(port)
= 0
= id
= state
print("Sensor Init")
("Sensor Init")
_# Thread's initialization method _
Thread.__init__(self)
except TypeError: _# Thread.__init__(self)
_# When an exception occurs, the following statement is output to remind the user to reenter the port number _#
print("Input error com, Please try new com number")
except InvalidIDError as e.
_# When an exception occurs, output the following statement to remind the user to re-enter the ID number _
print("Input error ID, Please try id : 0~99")
print()
... ...
_# The method used to indicate thread activity in a multithreaded thread.
_# All code in the run method (or code called inside this method) runs in a separate thread. _
def run(self): _# Declare global variables.
_# Declare a global variable, global lock.
global lock
_# Initialize count variable _
data_count = 0
_# Initialize sensor _
()
_# Turn on sensor_
()
while True: _# Generate data_ ()
_# Generate data _
data_count = data_count + 1
_# Raw signal
signal = (data_count) * 10
_# Analog noise_
noise = (0, 5)
_# Final data_ signal = int(signal + noise)
data = int(signal + noise)
_# Get mutex lock_
()
_# Receive commands
cmd = ()
_# Perform actions based on commands_
if cmd == SensorClass.STOP_CMD.
_# Stop the sensor if a stop command is received _
()
_# Output a message _# if cmd == SensorClass.STOP_CMD
print("Sensor stop work !!!")
print("Sensor stop work !!!")
elif cmd == SensorClass.SENDID_CMD.
_# Send the sensor ID number if the send ID command is received _
()
elif cmd == SensorClass.SENDVALUE_CMD.
_# If the send data command is received, send data_
(data)
elif cmd == SensorClass.NONE_CMD.
_# If no command is received _
print("Not Recv cmd!!!")
_# Release the mutex lock _
()
_# Delay 0.5s_
(0.5)
At the same time, here we need to modify the properties in the parent class of SensorClass, SerialClass, so that it doesn't keep blocking the process of receiving data:
_# Set timeout timeout _
= 0.5
In the main program, a mutex lock and a SensorClass object are created, and a new thread is started in the main thread to execute the run() method of the SensorClass object. In the main thread, the program keeps checking to see if the new thread has exited the run() method, and if it has not, it acquires the mutex lock and prints a message, then releases the mutex lock and delays for 0.5 seconds. When the new thread exits the run() method, the main thread outputs a debug message indicating the end of the multithreaded run.
The sample code is as follows:
if __name__ == "__main__".
# Create a mutex lock
lock = Lock()
# Initialize the thread
s_thread = SensorClass(port = "COM11",id = 0,state = SensorClass.WORK_MODE["RESPOND_MODE"])
# start the thread, the start method is executed in a concurrent manner
s_thread.start()
# The run() method is just a normal method of the class, it is still executed in the main thread
# s_thread.run()
# The join method ensures that the thread sub-thread finishes executing before the next thread can be executed.
# timeout is a timeout that ends the thread when it reaches its timeout.
# s_thread.join(timeout=5)
# Check if the s_thread thread has exited the run method
while s_thread.is_alive():: # Get the mutex lock.
# Acquire the mutex lock
()
# Print the message
print("Multi threaded work, This is the main thread for creating and running")
# Release the mutex lock
()
# Delay 0.5s
(0.5)
# End of multi-threaded running, output debug message
print("End of multi-threaded running")
Next we look at the results of the run:
As you can see, each program has a thread called the main thread. The code that is executed from the beginning is in this thread. s_thread is a subthread created in the main thread, and the new thread doesn't start running until we call the thread's start() method. We can also use the join method to make sure that the thread subthread finishes executing before the next thread is executed.
thread synchronization
In a multi-threaded environment, when multiple threads are simultaneously modifying a piece of data, it can produce unpredictable results. Consider a scenario where there is a list with all elements initialized to 0. The thread "set" traverses the list from back to front, modifying each element to 1, while the thread "print" traverses the list from front to back and prints its contents. If during the execution of these two threads, the thread "set" is interrupted by the thread "print" in the process of modifying the list, then the printed result may be that part of the elements in the list is 0 and the other part is 1, which is called the data inconsistency problem.
To solve this problem, we introduce the concept of locks. Locks have two states: locked and unlocked. When a thread, such as "set", needs to access shared data, it must first try to acquire the lock. If the lock has already been acquired by another thread, e.g. "print", then the thread "set" will be blocked until the thread "print" releases the lock. This ensures that only one thread can access the shared data at a time. As a result, when the list is printed, either all 0's or all 1's are output, thus avoiding the awkward situation of inconsistent data.
Python's Thread object provides two locking mechanisms, Lock and Rlock, for thread synchronization. Both provide acquire and release methods. For data or shared resources that need to be accessed by only one thread at a time, such as printing information to the console, you can place them between the acquire and release methods. In this way, we can ensure that data consistency and integrity are protected in a multithreaded environment.
In the sample code, we create and pass a mutually exclusive lock to the threads to ensure that both threads can safely call the Printf function to output relevant information.
# Acquiring a Mutual Exclusion Lock
()
# Printing Information
print("Multi threaded work,This is the main thread for creating and running")
# Releasing a Mutual Exclusion Lock
()
In addition to mutual exclusion locks and recursive locks, threads also have other methods applied to thread synchronization, such as signals, events, bars, etc., which are not overly explained here.
In fact, in order to efficiently manage memory, perform garbage collection, and call machine code in libraries, Python has a tool called a global interpreter lock (GIL). It cannot be turned off, which means that multithreading in Python is pseudo-multithreading; the Python interpreter can have multiple threads open, but only one thread is running in the interpreter at any one time.The GIL problem exists in the versions of Python implementations that most people use (e.g., CPython), and has been solved in a few versions of non-standard implementations such as IronPython and Jython.
Inter-thread communication
In addition to using thread synchronization methods such as mutex locks and recursive locks to ensure that shared memory is not accessed by two threads at the same time, we can also use the Queue module to ensure that data that needs to be interacted with in two threads is accessed safely. The Queue module provides synchronized, thread-safe queue classes, including the FIFO (first-in-first-out) queue Queue, LIFO (last-in-first-out) queue LifoQueue, and priority queue PriorityQueue. LifoQueue, and PriorityQueue.These queues all implement the lock primitive and can be used directly in multiple threads. Synchronization between threads can be achieved using queues.
thread pool
It is relatively expensive for the system to start a new thread because it requires interaction with the operating system. In this case, the use of thread pooling is an effective way to improve performance, especially when a program needs to create a large number of threads with short lifecycles, the use of thread pooling should be prioritized. Thread pool in the system startup that is pre-created a large number of idle threads, the program just submit the function to the thread pool, the thread pool will start a free thread to execute the function. When the function is executed, the thread does not terminate, but returns to the thread pool to continue to be idle, waiting for the next function to be executed.
In addition, thread pools help you control the number of concurrent threads in your system accurately. The presence of a large number of concurrent threads can cause significant performance degradation or even crash the Python interpreter. By setting a maximum number of threads, the thread pool can prevent the number of concurrent threads from exceeding the system's capacity, thus ensuring stable operation.
Starting with Python 3.2, the standard library provides us with modules, which provide the ThreadPoolExecutor and ProcessPoolExecutor classes.
In contrast to modules such as threading, this module returns a future object via submit, which are future-proof objects that are used for "call-and-answer" types of interactions, where the processing can take place in another thread and at some point in the future we can ask it for a result.
It allows you to get the status of a thread execution or the status and return value of a task execution:
① The main thread can get the state of a thread (or task), as well as the return value.
② When a thread finishes, the main thread can know it immediately.
The steps to perform a threaded task using a thread pool are as follows:
- Calls the constructor of the ThreadPoolExecutor class to create a thread pool;
- Define a normal function as a thread task;
- Call the submit() method of the ThreadPoolExecutor object to submit the thread task;
- Call the shutdown() method of the ThreadPoolExecutor object to shut down the thread pool.
multiprocess
Compared to multi-threading, multi-processing has a separate memory space and avoids the effects of global interpreter locks (GIL), making it more suitable for CPU-intensive tasks. The multiprocess module does this by mobilizing a new operating system process. On Windows machines, this operation is relatively expensive; on Linux, processes are implemented in the kernel in the same way as threads, so their expense is limited by the Python interpreter running in each process.
Multiprocessing in Python is implemented through the multiprocessing package, which is similar to multithreading in that it creates a process object using objects. The methods of this process object are similar to those of the thread object, including start(), run(), join(), etc. The Python multiprocessing implementation is similar to the multithreading implementation described above, in that you can use inheritance through classes.