Heim  >  Artikel  >  Backend-Entwicklung  >  Eine Einführung in die gemeinsame Nutzung von Ressourcen zwischen Threads und häufig verwendete Sperrmechanismen beim Python-Multithreading

Eine Einführung in die gemeinsame Nutzung von Ressourcen zwischen Threads und häufig verwendete Sperrmechanismen beim Python-Multithreading

不言
不言nach vorne
2018-10-26 17:18:592808Durchsuche

Dieser Artikel bietet Ihnen eine Einführung in die gemeinsame Nutzung von Ressourcen und häufig verwendete Sperrmechanismen zwischen Threads. Ich hoffe, dass er für Sie hilfreich ist.

In diesem Artikel werden kurz die Ressourcenfreigabe zwischen Threads und häufig verwendete Sperrmechanismen in der Multithread-Programmierung vorgestellt.

Bei der Multithread-Programmierung kommt es häufig zu Ressourcenfreigaben zwischen Threads:

  • Globale Variablen (global)

  • Warteschlange (aus der Warteschlangen-Importwarteschlange)

Häufig verwendeter Sperrmechanismus für die gemeinsame Nutzung von Ressourcen:

  • Sperre

  • RLock

  • Semphore

  • Bedingung

( 1) Ressourcenfreigabe zwischen Threads

  1. Die Verwendung globaler Variablen kann die Ressourcenfreigabe zwischen Threads realisieren, Stichwort global

Code-Demonstration:

from threading import Thread, Lock
lock = Lock()
total = 0

'''如果不使用lock那么,最后得到的数字不一定为0;同时loack不支持连续多次acquire,如果这样做了的后果是死锁!'''
def add():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total += 1
        lock.release()
    
def sub():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total -= 1
        lock.release()
    
thread1 = Thread(target=add)
thread2 = Thread(target=sub)


# 将Thread1和2设置为守护线程,主线程完成时,子线程也一起结束
# thread1.setDaemon(True)
# thread1.setDaemon(True)

# 启动线程
thread1.start()
thread2.start()

# 阻塞,等待线程1和2完成,如果不使用join,那么主线程完成后,子线程也会自动关闭。
thread1.join()
thread2.join()

total
  1. Verwenden Sie die Warteschlange, um Ressourcen zu teilen. Die Warteschlange ist threadsicher.

from threading import Thread, Lock
from queue import Queue

def add(q):
    if q.not_full:
        q.put(1)
    
def sub(q):
    if q.not_empty:
        recv = q.get()
        print(recv)
        q.task_done()
        
if __name__ =='__main__':
    # 设置q最多接收3个任务,Queue是线程安全的,所以不需要Lock
    qu = Queue(3)
    thread1 = Thread(target=add, args=(qu,))
    thread2 = Thread(target=sub, args=(qu,))
    thread1.start()
    thread2.start()
    # q队列堵塞,等待所有任务都被处理完。
    qu.join()

(2) Sperre (Sperre/RLock/Bedingung/Semphore)

  1. Sperre

Lock kann keine kontinuierlichen Sperren erwerben, da es sonst zu einem Deadlock kommen kann. Der Wettbewerb um Lock-Ressourcen kann zu einem Deadlock führen.

Sperre verringert die Leistung.

from threading import Thread, Lock
lock = Lock()
total = 0

'''如果不使用lock那么,最后得到的数字不一定为0;同时lock不支持连续多次acquire,如果这样做了的后果是死锁!'''
def add():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total += 1
        lock.release()
    
def sub():
    global total
    global lock
    for i in range(1000000):
        lock.acquire()
        total -= 1
        lock.release()
    
thread1 = Thread(target=add)
thread2 = Thread(target=sub)

# 将Thread1和2设置为守护线程,主线程完成时,子线程也一起结束
# thread1.setDaemon(True)
# thread1.setDaemon(True)

# 启动线程
thread1.start()
thread2.start()

# 阻塞,等待线程1和2完成,如果不使用join,那么主线程完成后,子线程也会自动关闭。
thread1.join()
thread2.join()
total
  1. RLock

RLock kann kontinuierlich Sperren erwerben, es ist jedoch eine entsprechende Anzahl von Freigaben erforderlich, um die Sperren freizugeben

weil es kontinuierlich erfasst werden kann Sperre, also wird die Funktion mit Sperre implementiert

  1. Bedingungsbedingungsvariable

Bedingungsbedingungsvariable gehorcht dem Kontext Verwaltungsprotokoll: Durch die Verwendung mit Statement wird die zugehörige Sperre für die Dauer des umschließenden Blocks erworben.

Die Methode wait() gibt die Sperre frei und blockiert sie dann, bis ein anderer Thread sie durch den Aufruf von notify() oder notify_all() aufweckt. Sobald wait() aktiviert ist, erhält es die Sperre erneut und kehrt zurück. Es kann auch ein Timeout angegeben werden.

Starten Sie zuerst die Wartefunktion, um das Signal in einem blockierten Wartezustand zu empfangen, und starten Sie dann die Benachrichtigungsfunktion, um das Signal zu senden

from threading import Thread, Lock, RLock
lock = RLock()
total = 0
def add():
    global lock
    global total
    # RLock实现连续获取锁,但是需要相应数量的release来释放资源
    for i in range(1000000):
        lock.acquire()
        lock.acquire()
        total += 1
        lock.release()
        lock.release()
def sub():
    global lock
    global total
    for i in range(1000000):
        lock.acquire()
        total -= 1
        lock.release()
thread1 = Thread(target=add)
thread2 = Thread(target=sub)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
total

  1. Semphore

Diese Klasse implementiert das Semaphorobjekt. Das Semaphor verwaltet einen atomaren Zähler, der die Anzahl der release()-Aufrufe abzüglich der Anzahl der acquire()-Aufrufe plus einen Anfangswert darstellt. Bei Bedarf blockiert die Methode „acquire()“, bis sie zurückkehren kann, ohne dass der Zähler negativ wird. Wenn nicht angegeben, ist der Wert standardmäßig 1.

from threading import Thread, Condition
'''聊天
    Peaple1 : How are you?
    Peaple2 : I`m fine, thank you!
    
    Peaple1 : What`s your job?
    Peaple2 : My job is teacher.
    
'''

def Peaple1(condition):
    with condition:
        print('Peaple1 : ', 'How are you?')
        condition.notify()
        condition.wait()
        
        print('Peaple1 : ', 'What`s your job?')
        condition.notify()
        condition.wait()

def Peaple2(condition):
    with condition:
        condition.wait()
        print('Peaple2 : ', 'I`m fine, thank you!')
        condition.notify()
        
        condition.wait()
        print('Peaple2 : ', 'My job is teacher.')
        condition.notify()


if __name__ == '__main__':
    cond = Condition()
    thread1 = Thread(target=Peaple1, args=(cond,))
    thread2 = Thread(target=Peaple2, args=(cond,))
    
    # 此处thread2要比thread1提前启动,因为notify必须要有wait接收;如果先启动thread1,没有wait接收notify信号,那么将会死锁。
    thread2.start()
    thread1.start()

#     thread1.join()
#     thread2.join()

(3) Eine kurze Einführung in die Multiprozessprogrammierung

  1. Bei der Multiprozessprogrammierung können globale Variablen nicht zwischen Prozessen gemeinsam genutzt werden, ebenso wenig wie queue.Queue

  2. Mehrprozessprogrammierung erfordert die Verwendung von Queue, Pipe
  3. Wenn Sie Prozesspoolprogrammierung verwenden, müssen Sie verwenden die Warteschlange der Manager-Instanz, um Kommunikation zu erreichen

Das obige ist der detaillierte Inhalt vonEine Einführung in die gemeinsame Nutzung von Ressourcen zwischen Threads und häufig verwendete Sperrmechanismen beim Python-Multithreading. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen