Thread introduction
- Thread is a processing task unit lower than the process. Sometimes it is also called lightweight process. It is the smallest unit of program execution flow. It can be said that multiple threads can be created in a process to process multiple tasks
- The components of a thread can be divided into thread ID, current system instruction pointer, register set and stack combination.
- Thread is an entity in a process and the basic unit independently scheduled and dispatched by the system. Thread does not have private system resources. There are one or more processes in the operating system. Each process has its own exclusive CPU resources. Different processes cannot share resources. However, if it is necessary to share CPU resources now, it can be realized through thread technology
- Threads are more lightweight control units than processes, and the cost of creating and destroying threads is less. Using threads can improve the processing performance of processes
- It is called multithreading technology to run multiple threads to complete different work at the same time in a single program
Modern processors are multi-core, multi-threaded execution programs, which seem to be carried out at the same time, but in fact, the CPU quickly switches between multiple threads
The threading module implements multithreading
Use the Thread class
Use format:
t=threading.Thread(target=None,name=None,args=())
parameter | describe |
---|---|
target | A function or method called when a thread starts |
name | Thread name |
args | The function requires an passed in parameter (in tuple form) |
Main methods of Thread object
method | brief introduction |
---|---|
run() | Method used to represent thread activity |
start() | Start thread |
join() | Wait until the thread terminates |
isAlive() | Determine whether the thread is active |
getName() | Returns the thread name |
setName() | Set thread name |
Functional thread creation
When creating a Thread, you only need to pass in an execution function and function parameters. The following example uses the Thread class to generate two sub threads and wait for them to end
import threading import time,os,random,math def printnum(num): for i in range(num): print(f'{threading.current_thread().getName()},{i}') time.sleep(1) if __name__=='__main__': t1=threading.Thread(target=printnum,args=(2,),name='thread1') t2=threading.Thread(target=printnum,args=(3,),name='thread2') t1.start() t2.start() t1.join() t2.join() print(f'{threading.current_thread().getName()}Thread end')
Operation results
Create thread class
Directly create a subclass of Thread to create a Thread object to realize multithreading
import threading,time class mythread(threading.Thread): def __init__(self,name,num): threading.Thread.__init__(self) self.name=name self.num=num def run(self): # The run() method is called automatically after the thread starts for i in range(self.num): print((f'{threading.current_thread().getName()},{i}')) time.sleep(1) if __name__=='__main__': t1=mythread('thread1',3) t2=mythread('thread2',2) t1.start() t2.start() t1.join() t2.join() print((f'{threading.current_thread().getName()}Thread end'))
Operation results
Two functions in the threading module get the active thread information
function | describe |
---|---|
active_count() | Gets the number of currently active threads |
encumerate() | Get the active thread information and return a list sequence |
Daemon thread
The main thread needs to wait for the execution of the child thread before continuing. If the child thread does not use the join() function, the main thread and the child thread run together and there is no dependency between them
Use format: thread object. setDaemon(True)
In multithreaded programming, if the child thread is set as the guardian thread of the main thread, it will be destroyed after waiting for the main thread to run. At this time, the premise of the guardian thread running is that the resident thread must exist
import threading import time def run(taskname): print(f'task-{taskname}') time.sleep(2) print(f'task-{taskname}completion of enforcement') if __name__=='__main__': for i in range(3): thread=threading.Thread(target=run,args=(f'{i}',)) thread.setDaemon(True) thread.start() print(f'Thread end:{threading.current_thread().getName()},The current number of threads is:{threading.active_count()}')
Operation results
You can see that after the main thread is executed, the program exits without waiting for the daemon thread to execute
Thread termination
The threading module does not provide a thread termination method, nor does it support directly stopping threads. Threads created through Thread() are independent of each other. If child threads are started in the main thread, they are also independent threads
Thread termination method
If you want to forcibly terminate the child thread while terminating the main thread, the simplest method is to set the child thread as the guardian thread, which is a way to stop the thread. There are other methods to stop the child thread
- Generate the thread object, put the complex business in the loop, set a stop flag bit for the thread object, and exit the loop once the flag bit reaches the predetermined value, so that the thread can be stopped
import threading import time class testthread(threading.Thread): def __init__(self): threading.Thread.__init__(self) self._running=True # Set thread flag bit def terminate(self): self._running=False def run(self): count=1 threadname=threading.current_thread().getName() while self._running: print(f'Thread Name:{threadname},Times:{count}') count+=1 time.sleep(1) if __name__=='__main__': t1=testthread() t1.start() time.sleep(3) # Wait for three seconds, and the number of periods is increased by 3 t1.terminate() # Modify the value of the flag bit and stop the child thread print('Main thread end')
2. Call the ctypes module to report an exception in the child thread and make the child thread exit
Multithreaded locking mechanism
The problem of lock mechanism is solved
When multiple threads modify global variables at the same time, there will be data security problems. In short, it is possible that multiple threads modify data successively, resulting in inconsistent data, also known as "dirty data"
Case 1: two threads modify one data at the same time
import threading num=10 def change_num(m,counter): global num for i in range(counter): num+=m num-=m if num!=10: # Create a warning statement. If the statement is executed, it indicates print(f'num The value of is:{num}') break if __name__=='__main__': t1=threading.Thread(target=change_num,args=(10,500000),name='Thread 1') t2=threading.Thread(target=change_num,args=(10,500000),name='Thread 2') t1.start() t2.start() t1.join() t2.join() print(f'Thread end:{threading.current_thread().getName()}')
Operation results
Through the running results, we can find that change_ The num() function should be added and then subtracted to ensure that the value of num is always 10, but the result is not the same. In fact, the scheduling of threads is determined by the system. Two threads are started at the same time to execute alternately. As long as the number of times is enough, the result of num may not be 10
Introduction to mutex
For thread safety, mutexes need to be used. When a thread wants to modify a data resource, it first locks it. At this time, the state of the resource is "locked", and other threads cannot change it. Other threads cannot lock the resource again until the thread releases the resource,
Meaning of mutex
Mutex ensures that only one thread can write at a time, thus ensuring the correctness of data
Core code of locking mechanism
# Create a lock object lock1=threading.Lock() # locking lock1.acquire() # release lock1.release()
Case 2: two threads modify the same data (lock)
import threading num=10 lock=threading.Loak() def change_num(m,counter): global num for i in range(counter): lock.acquire() # Acquire lock num+=m num-=m lock.release() # After the thread that obtains the lock runs out, it must release the lock, otherwise other threads will wait all the time and become dead threads if num!=10: print(f'num The value of is:{num}') break if __name__=='__main__': t1=threading.Thread(target=change_num,args=(10,500000),name='Thread 1') t2=threading.Thread(target=change_num,args=(10,500000),name='Thread 2') t1.start() t2.start() t1.join() t2.join() print(f'Thread end:{threading.current_thread().getName()}')
Operation results
In case 2 above, we are in change_ A lock mechanism is added to the num () function so that when a process executes change_ When the num () function is used, the lock will be obtained, while other threads will wait until the lock is obtained. In this way, when the two threads modify the global variable num, there will be no conflict, ensuring the security of the data