Maison >développement back-end >Tutoriel Python >Explication détaillée du verrouillage de synchronisation dans le thread Python

Explication détaillée du verrouillage de synchronisation dans le thread Python

不言
不言original
2018-04-27 10:01:311554parcourir

Cet article présente principalement en détail les informations pertinentes sur les verrous de synchronisation dans les threads python, qui ont une certaine valeur de référence. Les amis intéressés peuvent s'y référer

Dans les applications utilisant plusieurs threads, Comment assurer la sécurité des threads, la synchronisation entre les threads ou l'accès aux variables partagées sont des problèmes très difficiles. Ce sont également des problèmes rencontrés lors de l'utilisation du multi-threading, s'ils ne sont pas bien gérés, cela entraînera de graves conséquences. assurer la synchronisation entre les threads, et ce dernier assure l'exclusion mutuelle de l'accès aux variables partagées

Lock & RLock : le verrouillage Mutex est utilisé pour assurer l'accès multi-thread aux variables partagées
Objet Sémaphore : une version améliorée du Lock mutex, qui peut appartenir à plusieurs threads en même temps, tandis que le Lock ne peut appartenir qu'à un certain thread en même temps.
Objet événement : C'est une méthode de communication entre les threads, équivalente à un signal. Un thread peut envoyer un signal à un autre thread et ensuite le laisser effectuer une opération.
Objet Condition : il ne peut traiter les données qu'une fois que certains événements sont déclenchés ou que des conditions spécifiques sont remplies

1 Verrouillage (verrouillage mutex)

Demande de verrouillage – Entrer. le pool de verrous et attendez — Acquérir le verrou — Verrouillé — Libérer le verrou

Lock (verrouillage de commande) est la commande de synchronisation de niveau le plus bas disponible. Lorsque Lock est à l’état verrouillé, il n’appartient pas à un thread spécifique. Lock contient deux états : verrouillé et non verrouillé, ainsi que deux méthodes de base.

On peut considérer que Lock dispose d'un pool de verrous Lorsqu'un thread demande un verrou, le thread est placé dans le pool jusqu'à ce qu'il soit libéré du pool après avoir obtenu le verrou. Les threads du pool sont dans l’état de blocage synchrone dans le diagramme d’état.

Méthode de construction :
Lock()

Méthode d'instance :
acquire([timeout]) : Mettez le thread dans un état de blocage de synchronisation et essayez de obtenir la serrure.
release() : Libérez le verrou. Le thread doit avoir acquis le verrou avant utilisation, sinon une exception sera levée.

if mutex.acquire():
 counter += 1
 print "I am %s, set counter:%s" % (self.name, counter)
  mutex.release()

2. RLock (verrouillage réentrant)

RLock (verrouillage réentrant) est une instruction de synchronisation qui peut être demandé plusieurs fois par le même fil. RLock utilise les concepts de « thread possédé » et de « niveau de récursion ». Lorsqu'il est dans l'état verrouillé, RLock appartient à un thread. Le thread qui possède le RLock peut appeler à nouveau acquire() et doit appeler release() le même nombre de fois pour libérer le verrou.

On peut considérer que RLock contient un pool de verrous et un compteur avec une valeur initiale de 0. Chaque fois que acquire()/release() est appelé avec succès, le compteur va +1/-1 , et lorsqu'il vaut 0, le verrou est à l'état Déverrouillé.

Méthode de construction :
RLock()

Méthode d'instance :
acquire([timeout])/release() : similaire à Lock.

3. Sémaphore (accès aux objets partagés)

Parlons à nouveau de Sémaphore Pour être honnête, Sémaphore est le dernier verrou de synchronisation que j'ai utilisé dans le passé. où j'ai utilisé Rlock pour l'implémenter, ce qui est relativement compliqué. Après tout, Rlock nécessite un verrouillage et un déverrouillage par paires. . .

Semaphore gère un compteur intégré,
Le compteur intégré est de -1 chaque fois que acquire() est appelé
Le compteur intégré est de +1 lorsque release() est appelé ;
Le compteur ne peut pas être inférieur à 0 ; lorsque le compteur est à 0, acquire() bloquera le thread jusqu'à ce qu'un autre thread appelle release().

Allez directement dans le code, on contrôle le sémaphore à 3, c'est à dire que 3 threads peuvent utiliser ce verrou en même temps, et les threads restants ne peuvent que bloquer et attendre...

#coding:utf-8
#blog xiaorui.cc
import time
import threading

semaphore = threading.Semaphore(3)

def func():
 if semaphore.acquire():
  for i in range(3):
   time.sleep(1)
   print (threading.currentThread().getName() + '获取锁')
  semaphore.release()
  print (threading.currentThread().getName() + ' 释放锁')


for i in range(5):
 t1 = threading.Thread(target=func)
 t1.start()

4. Événement (communication entre les threads)

L'événement contient un indicateur en interne, qui est initialement faux.
Vous pouvez utiliser set() pour le définir sur true ;
Ou utiliser clear() pour le réinitialiser sur false
Vous pouvez utiliser is_set() pour vérifier l'état du drapeau ; 🎜>
Une autre fonction la plus importante est wait(timeout=None), qui est utilisée pour bloquer le thread actuel jusqu'à ce que le bit d'indicateur interne de l'événement soit défini sur true ou que le délai d'attente expire. Si l'indicateur interne est vrai, la fonction wait() comprend et renvoie.

import threading
import time

class MyThread(threading.Thread):
 def __init__(self, signal):
  threading.Thread.__init__(self)
  self.singal = signal

 def run(self):
  print "I am %s,I will sleep ..."%self.name
  self.singal.wait()
  print "I am %s, I awake..." %self.name

if __name__ == "__main__":
 singal = threading.Event()
 for t in range(0, 3):
  thread = MyThread(singal)
  thread.start()

 print "main thread sleep 3 seconds... "
 time.sleep(3)

 singal.set()

5. Condition (synchronisation des threads)

La condition peut être comprise comme un trivial avancé, qui fournit des fonctions plus avancées que Lock et RLock, nous permettant de contrôler les problèmes complexes de synchronisation des threads. threadiong.Condition maintient un objet threadion en interne (la valeur par défaut est RLock), qui peut être transmis en tant que paramètre lors de la création d'un objet Condigtion. La condition fournit également des méthodes d'acquisition et de libération, dont les significations sont cohérentes avec les méthodes d'acquisition et de libération de l'hôte. En fait, elles appellent simplement les méthodes correspondantes de l'objet hôte interne. Condition fournit également les méthodes suivantes (attention particulière : ces méthodes ne peuvent être appelées qu'après l'acquisition, sinon une exception RuntimeError sera signalée.) :

Condition.wait([ timeout]) :
La méthode wait libère la mémoire occupée en interne, et le thread est suspendu jusqu'à ce qu'il soit réveillé après réception d'une notification ou expire (si le paramètre timeout est fourni) . Lorsque le thread est réveillé et réoccupe le thread, le programme continue de s'exécuter.

Condition.notify() :
Réveiller un fil suspendu (si un fil suspendu existe). Remarque : La méthode notify() ne libérera pas la mémoire occupée.

Condition.notify_all()
Condition.notifyAll()

唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

对于Condition有个例子,大家可以观摩下。

from threading import Thread, Condition
import time
import random

queue = []
MAX_NUM = 10
condition = Condition()

class ProducerThread(Thread):
 def run(self):
  nums = range(5)
  global queue
  while True:
   condition.acquire()
   if len(queue) == MAX_NUM:
    print "Queue full, producer is waiting"
    condition.wait()
    print "Space in queue, Consumer notified the producer"
   num = random.choice(nums)
   queue.append(num)
   print "Produced", num
   condition.notify()
   condition.release()
   time.sleep(random.random())


class ConsumerThread(Thread):
 def run(self):
  global queue
  while True:
   condition.acquire()
   if not queue:
    print "Nothing in queue, consumer is waiting"
    condition.wait()
    print "Producer added something to queue and notified the consumer"
   num = queue.pop(0)
   print "Consumed", num
   condition.notify()
   condition.release()
   time.sleep(random.random())


ProducerThread().start()
ConsumerThread().start()

相关推荐:

python多线程之事件Event的使用详解

python线程池threadpool的实现

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn