Heim > Backend-Entwicklung > Python-Tutorial > Beispiel für Thread-Sperre in der Python-Programmierung

Beispiel für Thread-Sperre in der Python-Programmierung

高洛峰
Freigeben: 2017-02-28 17:28:39
Original
1415 Leute haben es durchsucht

Das Threading-Modul von Python bietet eine Vielzahl von sperrbezogenen Methoden. Da mehrere Threads in Python nicht gleichzeitig ausgeführt werden können, ist die Verwendung von Sperren sehr wichtig, um die Verwendung von Thread-Sperren in der Python-Programmierung zu erläutern.

Sperren

Pythons integrierte Datenstrukturen wie Listen und Wörterbücher sind Thread-sicher, einfache Datentypen wie Ganzzahlen und Gleitkommazahlen sind jedoch nicht Thread-sicher -safe. Diese einfache Datentyp-Passoperation erfordert die Verwendung von Sperren.

#!/usr/bin/env python3
# coding=utf-8

import threading

shared_resource_with_lock = 0
shared_resource_with_no_lock = 0
COUNT = 100000
shared_resource_lock = threading.Lock()

####LOCK MANAGEMENT##
def increment_with_lock():
  global shared_resource_with_lock
  for i in range(COUNT):
    shared_resource_lock.acquire()
    shared_resource_with_lock += 1
    shared_resource_lock.release()
    
def decrement_with_lock():
  global shared_resource_with_lock
  for i in range(COUNT):
    shared_resource_lock.acquire()
    shared_resource_with_lock -= 1
    shared_resource_lock.release()
    ####NO LOCK MANAGEMENT ##
  
def increment_without_lock():
  global shared_resource_with_no_lock
  for i in range(COUNT):
    shared_resource_with_no_lock += 1
  
def decrement_without_lock():
  global shared_resource_with_no_lock
  for i in range(COUNT):
    shared_resource_with_no_lock -= 1
  
####the Main program
if __name__ == "__main__":
  t1 = threading.Thread(target = increment_with_lock)
  t2 = threading.Thread(target = decrement_with_lock)
  t3 = threading.Thread(target = increment_without_lock)
  t4 = threading.Thread(target = decrement_without_lock)
  t1.start()
  t2.start()
  t3.start()
  t4.start()
  t1.join()
  t2.join()
  t3.join()
  t4.join()
  print ("the value of shared variable with lock management is %s"\
  %shared_resource_with_lock)
  print ("the value of shared variable with race condition is %s"\
  %shared_resource_with_no_lock)
Nach dem Login kopieren

Ausführungsergebnis:

$ ./threading_lock.py
Nach dem Login kopieren

the value of shared variable with lock management is 0
the value of shared variable with race condition is 0
Nach dem Login kopieren

Ein weiteres Beispiel:

import random
import threading
import time
logging.basicConfig(level=logging.DEBUG,
          format='(%(threadName)-10s) %(message)s',
          )
          
class Counter(object):
  def __init__(self, start=0):
    self.lock = threading.Lock()
    self.value = start
  def increment(self):
    logging.debug(time.ctime(time.time()))
    logging.debug('Waiting for lock')
    self.lock.acquire()
    try:
      pause = random.randint(1,3)
      logging.debug(time.ctime(time.time()))
      logging.debug('Acquired lock')      
      self.value = self.value + 1
      logging.debug('lock {0} seconds'.format(pause))
      time.sleep(pause)
    finally:
      self.lock.release()
def worker(c):
  for i in range(2):
    pause = random.randint(1,3)
    logging.debug(time.ctime(time.time()))
    logging.debug('Sleeping %0.02f', pause)
    time.sleep(pause)
    c.increment()
  logging.debug('Done')
counter = Counter()
for i in range(2):
  t = threading.Thread(target=worker, args=(counter,))
  t.start()
logging.debug('Waiting for worker threads')
main_thread = threading.currentThread()
for t in threading.enumerate():
  if t is not main_thread:
    t.join()
logging.debug('Counter: %d', counter.value)
Nach dem Login kopieren

Ausführungsergebnis:

$ python threading_lock.py
Nach dem Login kopieren

(Thread-1 ) Tue Sep 15 15:49:18 2015
(Thread-1 ) Sleeping 3.00
(Thread-2 ) Tue Sep 15 15:49:18 2015
(MainThread) Waiting for worker threads
(Thread-2 ) Sleeping 2.00
(Thread-2 ) Tue Sep 15 15:49:20 2015
(Thread-2 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:20 2015
(Thread-2 ) Acquired lock
(Thread-2 ) lock 2 seconds
(Thread-1 ) Tue Sep 15 15:49:21 2015
(Thread-1 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:22 2015
(Thread-1 ) Tue Sep 15 15:49:22 2015
(Thread-2 ) Sleeping 2.00
(Thread-1 ) Acquired lock
(Thread-1 ) lock 1 seconds
(Thread-1 ) Tue Sep 15 15:49:23 2015
(Thread-1 ) Sleeping 2.00
(Thread-2 ) Tue Sep 15 15:49:24 2015
(Thread-2 ) Waiting for lock
(Thread-2 ) Tue Sep 15 15:49:24 2015
(Thread-2 ) Acquired lock
(Thread-2 ) lock 1 seconds
(Thread-1 ) Tue Sep 15 15:49:25 2015
(Thread-1 ) Waiting for lock
(Thread-1 ) Tue Sep 15 15:49:25 2015
(Thread-1 ) Acquired lock
(Thread-1 ) lock 2 seconds
(Thread-2 ) Done
(Thread-1 ) Done
(MainThread) Counter: 4
Nach dem Login kopieren

Acquire() übergibt einen False-Wert, um zu prüfen, ob die Sperre erworben wurde. Zum Beispiel:

import logging
import threading
import time
logging.basicConfig(level=logging.DEBUG,
          format='(%(threadName)-10s) %(message)s',
          )
          
def lock_holder(lock):
  logging.debug('Starting')
  while True:
    lock.acquire()
    try:
      logging.debug('Holding')
      time.sleep(0.5)
    finally:
      logging.debug('Not holding')
      lock.release()
    time.sleep(0.5)
  return
          
def worker(lock):
  logging.debug('Starting')
  num_tries = 0
  num_acquires = 0
  while num_acquires < 3:
    time.sleep(0.5)
    logging.debug(&#39;Trying to acquire&#39;)
    have_it = lock.acquire(0)
    try:
      num_tries += 1
      if have_it:
        logging.debug(&#39;Iteration %d: Acquired&#39;,
               num_tries)
        num_acquires += 1
      else:
        logging.debug(&#39;Iteration %d: Not acquired&#39;,
               num_tries)
    finally:
      if have_it:
        lock.release()
  logging.debug(&#39;Done after %d iterations&#39;, num_tries)
lock = threading.Lock()
holder = threading.Thread(target=lock_holder,
             args=(lock,),
             name=&#39;LockHolder&#39;)
holder.setDaemon(True)
holder.start()
worker = threading.Thread(target=worker,
             args=(lock,),
             name=&#39;Worker&#39;)
worker.start()
Nach dem Login kopieren

Ausführungsergebnis:

$ python threading_lock_noblock.py
Nach dem Login kopieren

(LockHolder) Starting
(LockHolder) Holding
(Worker  ) Starting
(LockHolder) Not holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 1: Acquired
(LockHolder) Holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 2: Not acquired
(LockHolder) Not holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 3: Acquired
(LockHolder) Holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 4: Not acquired
(LockHolder) Not holding
(Worker  ) Trying to acquire
(Worker  ) Iteration 5: Acquired
(Worker  ) Done after 5 iterations
Nach dem Login kopieren

Thread-sichere Sperre

threading.RLock()
Nach dem Login kopieren

Gibt ein wiedereintrittsfähiges Sperrobjekt zurück. Eine Wiedereintrittssperre muss von dem Thread freigegeben werden, der sie erworben hat. Sobald ein Thread eine wiedereintrittsfähige Sperre erhält, kann derselbe Thread diese ohne Blockierung erneut erwerben und muss nach der Erfassung freigegeben werden.

Normalerweise kann ein Thread die Sperre nur einmal erwerben:

import threading

lock = threading.Lock()

print &#39;First try :&#39;, lock.acquire()
print &#39;Second try:&#39;, lock.acquire(0)
Nach dem Login kopieren

Ausführungsergebnis:

$ python threading_lock_reacquire.py
Nach dem Login kopieren

First try : True
Second try: False
Nach dem Login kopieren

Verwenden Sie RLock, um mehrere Sperren zu erhalten:

import threading
lock = threading.RLock()
print &#39;First try :&#39;, lock.acquire()
print &#39;Second try:&#39;, lock.acquire(0)
Nach dem Login kopieren

Ausführungsergebnis:

python threading_rlock.py
Nach dem Login kopieren

First try : True
Second try: 1
Nach dem Login kopieren

Schauen wir uns ein weiteres Beispiel an:

#!/usr/bin/env python3
# coding=utf-8
import threading
import time
class Box(object):
  lock = threading.RLock()
  def __init__(self):
    self.total_items = 0
  def execute(self,n):
    Box.lock.acquire()
    self.total_items += n
    Box.lock.release()
  def add(self):
    Box.lock.acquire()
    self.execute(1)
    Box.lock.release()
  def remove(self):
    Box.lock.acquire()
    self.execute(-1)
    Box.lock.release()
    
## These two functions run n in separate
## threads and call the Box&#39;s methods    
def adder(box,items):
  while items > 0:
    print ("adding 1 item in the box\n")
    box.add()
    time.sleep(5)
    items -= 1
    
def remover(box,items):
  while items > 0:
    print ("removing 1 item in the box")
    box.remove()
    time.sleep(5)
    items -= 1
    
## the main program build some
## threads and make sure it works
if __name__ == "__main__":
  items = 5
  print ("putting %s items in the box " % items)
  box = Box()
  t1 = threading.Thread(target=adder,args=(box,items))
  t2 = threading.Thread(target=remover,args=(box,items))
  t1.start()
  t2.start()
  t1.join()
  t2.join()
  print ("%s items still remain in the box " % box.total_items)
Nach dem Login kopieren

Ausführungsergebnis:

$ python3 threading_rlock2.py
Nach dem Login kopieren

putting 5 items in the box 
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
removing 1 item in the box
adding 1 item in the box
removing 1 item in the box
adding 1 item in the box
0 items still remain in the box
Nach dem Login kopieren

Weitere Beispiele für Artikel zum Thema Thread-Sperren in der Python-Programmierung finden Sie auf der chinesischen PHP-Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage