GILSon nom complet estGlobal Interpreter Lock(Global Interpreter Lock),Pour la sécurité des données,GILAssurez - vous qu'un seul thread reçoit les données en même temps.Alors...,InpythonMoyenne, Un seul thread peut être exécuté en même temps .
EtIODense,Le Multithreading améliore l'efficacité( Il y aIOL'opération aura lieuIOAttendez.,Une perte de temps inutile,Et l'ouverture de multithreads peut être faite dans le threadAEn attente,Passer automatiquement au threadB,Peut ne pas gaspillerCPURessources,Afin d'améliorer l'efficacité de l'exécution du programme ).Alors...pythonPaire multithreadéeIOCode dense plus convivial.
EtCPUDense( Divers traitements cycliques、Calcul, etc ), En raison de la charge de calcul , Le minuteur atteindra bientôt le seuil ,Et puisDéclencheurGILLibération et remise en concurrence de( Passer d'un thread à l'autre nécessite certainement des ressources ),Alors...pythonPaire multithreadéeCPULe Code dense n'est pas convivial.
PythonLors de l'utilisation de multithreads,AppelécLe fil natif de la langue.
Notes: Certains ne comprennent pas ?
threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
En appelant ce constructeur , Doit avoir un paramètre clé .Les paramètres sont les suivants::
group Ça devrait être None;Pour l'expansion future ThreadGroup Classe implémentée avec maintien .
target C'est pour run() Méthode appeléeObjet appelable(Une fonction).Par défaut None, Indique qu'aucune méthode n'a besoin d'être appelée .
name - Oui.Nom du thread.Par défaut,Par “Thread-N” Le format constitue un nom unique ,Parmi eux N C'est un petit nombre décimal . Plusieurs Threads peuvent avoir le même nom .
args Est utilisé pour appeler la fonction cible Tuples de paramètres.Par défaut ().
kwargs Est utilisé pour appeler la fonction cible Dictionnaire des paramètres clés .Par défaut {}.
daemon Paramètre sinon None, Définit explicitement si le thread est en mode démon . Si oui None (Par défaut),Le thread vaSuccessionDu thread courant Propriétés du mode démon .
3.3 La version et au - dessus ont cette propriété .
Attention!:Assurez - vous d'appeler start() C'est réglé ,Sinon, ça va sortir RuntimeError .
La valeur initiale est héritée du thread create ; Le thread principal n'est pas un thread gardien , Par conséquent, tous les Threads créés par le thread principal sont par défaut daemon = False.
Quand il n'y a pas de fils non - gardiens vivants ,ToutPythonLe programme va sortir.
Si le Sous - type ** Surcharge du constructeur ,** Il doit s'assurer que Avant de faire quoi que ce soit ,Commencez par Appeler le constructeur de classe de base (Thread.init()).
Interprétation des termes:Mode gardien
Il y a un type de thread,C'est dansEn coulissesDe, Sa mission est de servir d'autres fils ,Ce fil s'appelle“Fil de fond(Daemon Thread)”,Aussi appelé“Fils de démon”Ou“Les fils elfes”.Python Le thread de collecte des ordures de l'interpréteur est un Thread de fond typique .
Le fil de fond a une caractéristique , Si tous les fils de la réception sont morts , Alors le fil de fond meurt automatiquement .
Démarrer l'activité thread .
Il est là.Un fil C'est le plus grand. Il ne peut être appelé qu'une seule fois. Il arrange les objets run() La méthode est appelée dans un processus de contrôle indépendant .
Si la méthode est appelée dans le même objet thread Plus d'une fois ,Oui.Jetez RuntimeError .
Attendez., Jusqu'à la fin du thread .
C'est vrai.Blocage Le thread qui appelle cette méthode ,Jusqu'à ce qu'il soit appelé join() Fin du fil pour .
Quand timeout Paramètres Existe et n'est pas None Heure, Il devrait s'agir d'un délai d'action spécifié pour SecondesEn unitésNombre de points flottants(Ou score).
Parce que join() Toujours revenir None , Vous devez donc être join() AprèsAppelezis_alive() Pour déterminer si un délai s'est produit ,Si le fil est toujours vivant,Et join() Temps mort.
Quand timeout Le paramètre n'existe pas ou None ,Cette opération va Blocage jusqu'à la fin du fil .
Un filPeut être join() Plusieurs fois..
import threading # Module thread
import time
def run(n):
print("task", n)
time.sleep(1)
print('2s')
time.sleep(1)
print('3s')
if __name__ == '__main__':
th = threading.Thread(target=run,name="thread_1" args=("thread 1",), daemon=True) # Créer un thread
# Définir le Sous - processus comme un fil de démon ,**Il doit êtrestart()Réglage précédent
th.setDaemon(True) # Configurer les fils du démon, En fait, au moment de la création C'est réglé. daemon=True
th.start()
# Définir le thread principal pour attendre la fin du sous - thread
th.join()
print("end")
Parce qu'il y a une programmation aléatoire entre les fils,Et chaque thread ne peut exécuter quenAprès l'exécution de l'article, Cela peut se produire lorsque plusieurs Threads modifient simultanément les mêmes données Données sales(Notes:PythonType de données de base、Liste、Tuple、 Les dictionnaires sont sans fil , Il n'y aura donc pas d'écrasement du programme , Mais il en résulte une valeur inconnue pour les données ,Données sales),
Donc il y a un verrou de fil,C'est - à - dire qu'un thread est autorisé à fonctionner en même temps. Le verrouillage par fil est utilisé pour verrouiller les ressources , Plusieurs serrures peuvent être définies ,Comme le code ci - dessous, Quand il faut monopoliser une ressource , N'importe quelle serrure peut verrouiller cette ressource , C'est comme si vous pouviez verrouiller la même porte avec différentes serrures .
Parce que les fils sont programmés au hasard,Si plusieurs Threads manipulent un objet en même temps, Et l'objet n'est pas bien protégé ,Résultats inattendus du programme,C'est pour ça qu'on l'appelle aussi“Thread Unsafe”.
Pour éviter ce qui précède, Et la serrure est apparue .
Je suis5EspècePythonVerrouillage du fil Il est détaillé dans .
Supplément conceptuel:
Les points suivants 5 Différentes formes d'interprétation join Utilisation dans la programmation multithreadée
Python Par défaut pour Multithreading (Définir le threadsetDaemon(False)),Une fois que le thread principal a terminé sa tâche,J'ai arrêté.,À ce stade, le Sous - thread poursuit sa tâche,Jusqu'à la fin de sa mission
Notes:setDaemon(False) C'est - à - dire: Le thread est défini comme un thread non - démon ; Après la sortie du programme principal , Les sous - fils ne sortent pas automatiquement .
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(3)
print("Thread1 J'ai reçu l'ordre de couvrir ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print("Thread2 J'ai reçu l'ordre de couvrir ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = [] # Liste des Threads
# Créer et ouvrir des fils1
thread1 = threading.Thread(target = doWaiting1)
thread1.start() # start()Fonctions Appel réel RUN()Fonctions(PythonAppelé CThread for Language)
tsk.append(thread1)
# Créer et ouvrir des fils2
thread2 = threading.Thread(target = doWaiting2)
thread2.start()
tsk.append(thread2)
# Programme de chronométrage
print('start join: ' + time.strftime('%H:%M:%S') )
print('end join: ' + time.strftime('%H:%M:%S') )
Résultats des opérations
start waiting1: 20:03:30
start waiting2: 20:03:30
start join: 20:03:30
end join: 20:03:30 # Le fil principal est terminé ici , Et les sous - fils continuent à travailler
Thread1 J'ai reçu l'ordre de couvrir # Sous - thread1 Continuez à travailler
stop waiting1: 20:03:33
Thread2 J'ai reçu l'ordre de couvrir
stop waiting2: 20:03:38
Conclusions:
Pour ouvrir le fil**setDaemon(True),**Définir le thread enfant comme un thread gardien, Mettre en œuvre la fin du programme principal , Le Sous - programme termine immédiatement toutes les fonctions
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(3)
print("Thread1 J'ai reçu l'ordre de couvrir ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print("Thread2 J'ai reçu l'ordre de couvrir ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = []
# Créer et ouvrir des fils1
thread1 = threading.Thread(target = doWaiting1)
thread1.setDaemon(True)
thread1.start()
tsk.append(thread1)
# Créer et ouvrir des fils2
thread2 = threading.Thread(target = doWaiting2)
thread2.setDaemon(True)
thread2.start()
tsk.append(thread2)
print('start join: ' + time.strftime('%H:%M:%S') )
print('end join: ' + time.strftime('%H:%M:%S') )
Résultats des opérations:
start waiting1: 20:10:04
start waiting2: 20:10:04
start join: 20:10:04
end join: 20:10:04 # Une fois le fil principal terminé, Le Sous - fil se termine immédiatement , Quel que soit l'état .
Conclusions:
Fils non gardiens, Le programme principal attendra que tous les sous - programmes soient exécutés avant de se terminer
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(3)
print("Thread1 J'ai reçu l'ordre de couvrir ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print("Thread2 J'ai reçu l'ordre de couvrir ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = []
# Créer et ouvrir des fils1
thread1 = threading.Thread(target = doWaiting1)
thread1.start()
tsk.append(thread1)
# Créer et ouvrir des fils2
thread2 = threading.Thread(target = doWaiting2)
thread2.start()
tsk.append(thread2)
print('start join: ' + time.strftime('%H:%M:%S') )
for t in tsk:
print('%s Voilà le fil '%t)
t.join() # Threadjoin() C'est - à - dire:: Les deux fils tournent à nouveau , Ne passez pas à la ligne suivante tant que vous n'avez pas terminé
print('end join: ' + time.strftime('%H:%M:%S') )
Résultats des opérations:
start waiting1: 20:14:35
start waiting2: 20:14:35
start join: 20:14:35
<Thread(Thread-1, started 19648)> Voilà le fil
Thread1 J'ai reçu l'ordre de couvrir
stop waiting1: 20:14:38
<Thread(Thread-2, started 24056)> Voilà le fil
Thread2 J'ai reçu l'ordre de couvrir
stop waiting2: 20:14:43
end join: 20:14:43 # Une fois les deux Threads terminés , Pour que ça marche
Conclusions:
Voilà.joinParamètrestimeoutValeur numérique, Le Sous - thread n'est pas terminé après avoir jugé qu'il y a beaucoup d'attente , Alors le fil principal n'attend plus
Notes:join Après avoir réglé le délai ,Base de jugement Sous - thread terminé | Temps mort (Logique ou relationnelle), C'est - à - dire deux conditions qui sont vraies en premier , Faites - le descendre .
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(2)
print("Thread1 J'ai reçu l'ordre de couvrir ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print("Thread2 J'ai reçu l'ordre de couvrir ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = []
# Créer et ouvrir des fils1
thread1 = threading.Thread(target = doWaiting1)
thread1.start()
tsk.append(thread1)
# Créer et ouvrir des fils2
thread2 = threading.Thread(target = doWaiting2)
thread2.start()
tsk.append(thread2)
print('start join: ' + time.strftime('%H:%M:%S') )
for t in tsk:
print("C'est parti.:"+time.strftime('%H:%M:%S'))
print('%s Voilà le fil '%t)
t.join(5)
print("Fin:" + time.strftime('%H:%M:%S'))
print('end join: ' + time.strftime('%H:%M:%S') )
Résultats des opérations:
start waiting1: 21:14:25
start waiting2: 21:14:25
start join: 21:14:25
C'est parti.:21:14:25
<Thread(Thread-1, started 22348)> Voilà le fil
Thread1 J'ai reçu l'ordre de couvrir
stop waiting1: 21:14:27
Fin:21:14:27
C'est parti.:21:14:27
<Thread(Thread-2, started 13164)> Voilà le fil
Fin:21:14:32
end join: 21:14:32
Thread2 J'ai reçu l'ordre de couvrir
stop waiting2: 21:14:33
Conclusions:
Le Sous - thread qui a expiré et n'a pas terminé le traitement sera terminé directement ( Caractéristiques compatibles avec les fils du démon )
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(2)
print("Thread1 J'ai reçu l'ordre de couvrir ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print("Thread2 J'ai reçu l'ordre de couvrir ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = []
# Créer et ouvrir des fils1
thread1 = threading.Thread(target = doWaiting1)
thread1.setDaemon(True) # Fils de démon
thread1.start()
tsk.append(thread1)
# Créer et ouvrir des fils2
thread2 = threading.Thread(target = doWaiting2)
thread2.setDaemon(True) # Fils de démon
thread2.start()
tsk.append(thread2)
print('start join: ' + time.strftime('%H:%M:%S') )
for t in tsk:
print("C'est parti.:"+time.strftime('%H:%M:%S'))
print('%s Voilà le fil '%t)
t.join(5)
print("Fin:" + time.strftime('%H:%M:%S'))
print('end join: ' + time.strftime('%H:%M:%S') )
Résultats des opérations:
start waiting1: 21:24:14
start waiting2: 21:24:14
start join: 21:24:14
C'est parti.:21:24:14
<Thread(Thread-1, started daemon 9060)> Voilà le fil
Thread1 J'ai reçu l'ordre de couvrir
stop waiting1: 21:24:16
Fin:21:24:16
C'est parti.:21:24:16
<Thread(Thread-2, started daemon 13912)> Voilà le fil
Fin:21:24:21
end join: 21:24:21
Conclusions: