Python third-party library --threading module

Introduction to threads

  1. A thread is a processing task unit lower than a process . It is sometimes called a 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.
  2. The components of a thread can be divided into thread ID, current system instruction pointer, register set, stack combination.
  3. A thread is an entity in a process, the basic unit independently scheduled and dispatched by the system. A thread does not own private system resources. There are one or more processes in the operating system, and each process has its own exclusive CPU resources. Resource sharing is not possible, but if CPU resource sharing is required now, it can be achieved through threading technology
  4. Threads are more lightweight control units than processes, and the cost of creating and destroying threads is smaller. Using threads can improve the processing performance of processes
  5. Running multiple threads in a single program to complete different work at the same time is called multi-threading technology

Modern processors are multi-core multi-threaded execution programs that appear to be running at the same time, but in fact, the CPU quickly switches execution between multiple threads.

The threading module implements multithreading

Use the Thread class in
it using the format:

t=threading.Thread(target=None,name=None,args=())
parameter describe
target The function or method called when the thread starts
name thread name
args The parameters that the function needs to pass in (tuple form)

The main method of the Thread object

method Introduction
run() Methods used to represent thread activity
start() start thread
join() wait until thread terminates
isAlive() Determine if a thread is active
getName() return thread name
setName() set thread name

Create a thread functionally

When creating a thread, you only need to pass in an execution function and the parameters of the function. The following example uses the Thread class to generate two child 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()}线程结束')

operation result
insert image description here

Create thread class

Create a subclass of Thread directly to create a thread object for 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):		# 线程启动后自动调用run()方法
        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()}线程结束'))

operation result
insert image description here

Two functions in the threading module obtain active thread information

function describe
active_count() Get the current number of active threads
encumerate () Get active thread information, return a list sequence

Daemon thread

The main thread needs to wait for the sub-thread to finish executing before continuing. If the sub-thread does not use the join() function, the main thread and the sub-thread will run together, and there is no dependency between them.
Usage format: 线程对象.setDaemon(True)
In multi-threaded programming, if the sub-thread is set to The daemon thread designated as the main thread will be destroyed after waiting for the main thread to run. At this time, the living thread must exist for the daemon thread to run.

import threading
import time
def run(taskname):
    print(f'任务-{
      
      taskname}')
    time.sleep(2)
    print(f'任务-{
      
      taskname}执行完毕')
if __name__=='__main__':
    for i in range(3):
        thread=threading.Thread(target=run,args=(f'{
      
      i}',))
        thread.setDaemon(True)
        thread.start()
    print(f'线程结束:{
      
      threading.current_thread().getName()},当前线程数量为:{
      
      threading.active_count()}')    

Running results
insert image description here
You can see that after the main thread is executed, the program exits without waiting for the daemon thread to finish executing.

thread terminated

The threading module does not provide a thread termination method, nor does it support directly stopping the thread. The threads created by Thread() are independent of each other. If the sub-thread is started in the main thread, the two are also independent
thread termination methods.
If you want to Forcibly terminate the child thread at the same time as the main thread is terminated, the easiest way is to set the child thread as a daemon thread, this is one way to stop the thread, there are other ways to stop the child thread

  1. Generate a thread object, put the complex business in the loop, set a stop flag for the thread object, and exit the loop once the flag reaches a 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		# 设置线程标志位
    def terminate(self):
        self._running=False
    def run(self):
        count=1
        threadname=threading.current_thread().getName()
        while self._running:
            print(f'线程名称:{
      
      threadname},次数:{
      
      count}')
            count+=1
            time.sleep(1)
if __name__=='__main__':
    t1=testthread()
    t1.start()
    time.sleep(3)		# 等待三秒,期间次数加3
    t1.terminate()		# 修改标志位的值,停止子线程
    print('主线程结束')

insert image description here
2. Called by the ctypes module, an exception is reported in the child thread, so that the child thread exits

Multi-threaded locking mechanism

The problem solved by the locking mechanism
There will be data security problems when multiple threads modify global variables at the same time. Simply put, 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:		# 创建一个警示语句,如果该语句被执行则说明
            print(f'num的值为:{
      
      num}')
            break
if __name__=='__main__':
    t1=threading.Thread(target=change_num,args=(10,500000),name='线程1')
    t2=threading.Thread(target=change_num,args=(10,500000),name='线程2')
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f'线程结束:{
      
      threading.current_thread().getName()}')

Running results
insert image description here
From the running results, we can find that the change_num() function should ensure that the value of num is always 10 by adding and then subtracting, but the result is not the case. In fact, the scheduling of threads is determined by the system to start two threads alternately at the same time, as long as The number of times is enough, the result of num is not necessarily 10

Introduction to mutex locks
For thread safety, mutex locks need to be used. When a thread wants to modify a data resource, it will be locked first. At this time, the state of the resource is "locked", and other threads cannot change it until the thread releases the resource. , other threads can lock the resource again, the
meaning
of the mutex lock The mutex lock ensures that only one thread performs the write operation at a time, thus ensuring the correctness of the data
The core code of the lock mechanism

# 创建一个锁对象
lock1=threading.Lock()
# 锁定
lock1.acquire()
# 释放
lock1.release()

Case 2: Two threads modify the same data (locking)

import threading

num=10
lock=threading.Loak()
def change_num(m,counter):
    global num
    for i in range(counter):
    	lock.acquire()		# 获取锁
        num+=m
        num-=m
        lock.release()		# 获得锁的线程用完后一定要释放锁,否则其它线程就会一直等待下去,从而成为死线程
        if num!=10:		
            print(f'num的值为:{
      
      num}')
            break
if __name__=='__main__':
    t1=threading.Thread(target=change_num,args=(10,500000),name='线程1')
    t2=threading.Thread(target=change_num,args=(10,500000),name='线程2')
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f'线程结束:{
      
      threading.current_thread().getName()}')

operation result
insert image description here

In the second case above, we added a lock mechanism to the change_num() function, so that when a process executes the change_num() function, it will acquire the lock, and other threads will wait until the lock is acquired, so that two threads When modifying the global variable num, there will be no conflict, ensuring data security

Guess you like

Origin blog.csdn.net/m0_54510474/article/details/120589862