ホームページ  >  記事  >  バックエンド開発  >  Pythonプログラミングにおけるスレッドロックの例

Pythonプログラミングにおけるスレッドロックの例

高洛峰
高洛峰オリジナル
2017-02-28 17:28:391393ブラウズ

Python のスレッド モジュールは、さまざまなロック関連のメソッドを提供します。Python の複数のスレッドは同時に実行できないため、ロックの使用は非常に重要です。Python プログラミングでのスレッド ロックの使用を説明する例を見てみましょう。

Locks

リストや辞書などの Python の組み込みデータ構造はスレッドセーフですが、整数や浮動小数点数などの単純なデータ型はスレッドセーフではありません。これらの単純なデータ型を操作するには、次を使用する必要があります。ロック。

#!/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)

実行結果:

$ ./threading_lock.py

the value of shared variable with lock management is 0
the value of shared variable with race condition is 0

別の例:

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)

実行結果:

$ python threading_lock.py

(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

acquire() False 値を渡すことで、ロックが取得されているかどうかを確認できます。例:

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

実行結果:

$ python threading_lock_noblock.py

(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

スレッドセーフロック

threading.RLock()

Return再入可能なロック オブジェクト。再入可能なロックは、それを取得したスレッドによって解放される必要があります。スレッドがリエントラント ロックを取得すると、同じスレッドはブロックせずに再度そのロックを取得でき、取得後に解放する必要があります。

通常、スレッドはロックを 1 回だけ取得できます:

import threading

lock = threading.Lock()

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

実行結果:

$ python threading_lock_reacquire.py

First try : True
Second try: False

RLock を使用して複数のロックを取得できます:

りー

処刑結果:

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

python threading_rlock.py

別の例を見てみましょう:

First try : True
Second try: 1

実行結果:

#!/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)

$ python3 threading_rlock2.py

その他の例 スレッドロックに関連する記事をお読みください。 Python プログラミング PHP 中国語 Web サイトをフォローしてください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。