Bibliothèque tierce Python --threading module

Présentation des threads

  1. Un thread est une unité de tâche de traitement inférieure à un processus . Il est parfois appelé processus léger. Il s'agit de la plus petite unité de flux d'exécution de programme. On peut dire que plusieurs threads peuvent être créés dans un processus pour traiter plusieurs tâches.
  2. Les composants d'un thread peuvent être divisés en ID de thread, pointeur d'instruction système actuel, jeu de registres, combinaison de pile.
  3. Un thread est une entité dans un processus, l'unité de base qui est indépendamment planifiée et distribuée par le système. Un thread n'a pas de ressources système privées. Il existe un ou plusieurs processus dans le système d'exploitation, et chaque processus a son propre processeur exclusif. Le partage des ressources n'est pas possible, mais si le partage des ressources CPU est requis maintenant, il peut être réalisé grâce à la technologie de threading
  4. Les threads sont des unités de contrôle plus légères que les processus, et le coût de création et de destruction des threads est moindre. L'utilisation des threads peut améliorer les performances de traitement des processus.
  5. L'exécution de plusieurs threads dans un seul programme pour effectuer différents travaux en même temps est appelée technologie multi-threading.

Les processeurs modernes sont des programmes d'exécution multicœurs multithreads qui semblent s'exécuter en même temps, mais en fait, le processeur bascule rapidement l'exécution entre plusieurs threads.

Le module de threading implémente le multithreading

Utilisez la classe Thread en
utilisant le format :

t=threading.Thread(target=None,name=None,args=())
paramètre décrire
cibler La fonction ou la méthode appelée au démarrage du thread
Nom nom du fil
arguments Les paramètres que la fonction doit transmettre (sous forme de tuple)

La méthode principale de l'objet Thread

méthode Introduction
Cours() Méthodes utilisées pour représenter l'activité des threads
Démarrer() démarrer le fil
rejoindre() attendre que le thread se termine
est vivant() Déterminer si un thread est actif
obtenirNom() retourner le nom du fil
setName() définir le nom du fil

Créer un fil de manière fonctionnelle

Lors de la création d'un thread, il vous suffit de transmettre une fonction d'exécution et les paramètres de la fonction. L'exemple suivant utilise la classe Thread pour générer deux threads enfants et attendre qu'ils se terminent

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()}线程结束')

résultat de l'opération
insérez la description de l'image ici

Créer une classe de thread

Créez une sous-classe de Thread directement pour créer un objet thread pour le 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()}线程结束'))

résultat de l'opération
insérez la description de l'image ici

Deux fonctions dans le module de threading obtiennent des informations sur le thread actif

une fonction décrire
active_count() Obtenir le nombre actuel de threads actifs
encombrer () Obtenir des informations sur le thread actif, renvoyer une séquence de liste

Fil démon

Le thread principal doit attendre que le sous-thread ait fini de s'exécuter avant de continuer. Si le sous-thread n'utilise pas la fonction join() , le thread principal et le sous-thread s'exécuteront ensemble et il n'y a pas de dépendance entre eux .
Format d'utilisation : 线程对象.setDaemon(True)
dans la programmation multithread, si le sous-thread est défini sur Le thread démon désigné comme thread principal sera détruit après avoir attendu que le thread principal s'exécute. À ce stade, le thread vivant doit exister pour le démon fil à exécuter.

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()}')    

Résultats de l'exécution
insérez la description de l'image ici
Vous pouvez voir qu'après l'exécution du thread principal, le programme se termine sans attendre que le thread démon ait fini de s'exécuter.

fil terminé

Le module de threading ne fournit pas de méthode de terminaison de thread, ni ne prend en charge l'arrêt direct du thread. Les threads créés par Thread() sont indépendants les uns des autres. Si le sous-thread est démarré dans le thread principal, les deux sont également indépendants
méthodes de terminaison de thread.
Si vous souhaitez terminer de force le thread enfant en même temps que le thread principal est terminé, le moyen le plus simple est de définir le thread enfant comme un thread démon, c'est une façon d'arrêter le thread, il existe d'autres façons d'arrêter le thread enfant

  1. Générer un objet thread, placer des affaires complexes dans la boucle, définir un indicateur d'arrêt pour l'objet thread et quitter la boucle une fois que l'indicateur atteint une valeur prédéterminée, afin que le thread puisse être arrêté
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('主线程结束')

insérez la description de l'image ici
2. Appelé par le module ctypes, une exception est signalée dans le thread enfant, de sorte que le thread enfant se termine

Mécanisme de verrouillage multi-filetage

Le problème résolu par le mécanisme de verrouillage
Il y aura des problèmes de sécurité des données lorsque plusieurs threads modifient des variables globales en même temps. En termes simples, il est possible que plusieurs threads modifient les données successivement, ce qui entraîne des données incohérentes, également appelées "données modifiées".

Cas 1 : Deux threads modifient une donnée en même temps

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()}')

Résultats en cours
insérez la description de l'image ici
D'après les résultats en cours, nous pouvons constater que la fonction change_num() doit s'assurer que la valeur de num est toujours 10 en ajoutant puis en soustrayant, mais le résultat n'est pas le cas. En fait, la planification des threads est déterminée par le système pour démarrer deux threads alternativement en même temps, tant que le nombre de fois est suffisant, le résultat de num n'est pas nécessairement 10

Introduction aux verrous mutex
Pour la sécurité des threads, les verrous mutex doivent être utilisés. Lorsqu'un thread veut modifier une ressource de données, il sera d'abord verrouillé. À ce stade, l'état de la ressource est "verrouillé" et les autres threads ne peuvent pas changer jusqu'à ce que le thread libère la ressource. , d'autres threads peuvent à nouveau verrouiller la ressource, la
signification
du verrou mutex Le verrou mutex garantit qu'un seul thread effectue l'opération d'écriture à la fois, garantissant ainsi l'exactitude des données
Le code principal de le mécanisme de verrouillage

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

Cas 2 : Deux threads modifient les mêmes données (verrouillage)

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()}')

résultat de l'opération
insérez la description de l'image ici

Dans le second cas ci-dessus, nous avons ajouté un mécanisme de verrouillage à la fonction change_num(), de sorte que lorsqu'un processus exécute la fonction change_num(), il acquiert le verrou, et les autres threads attendent que le verrou soit acquis, de sorte que deux threads Lors de la modification de la variable globale num, il n'y aura pas de conflit, assurant la sécurité des données

Je suppose que tu aimes

Origine blog.csdn.net/m0_54510474/article/details/120589862
conseillé
Classement