Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung der einfachen Verwendung von Python-Multithreading, Sperren und Ereignismechanismen

Detaillierte Erläuterung der einfachen Verwendung von Python-Multithreading, Sperren und Ereignismechanismen

不言
不言Original
2018-04-27 11:52:121506Durchsuche

Dieser Artikel stellt hauptsächlich die einfache Verwendung von Python-Multithreading, Sperren und Ereignismechanismen vor. Jetzt teile ich ihn mit Ihnen und gebe ihm eine Referenz. Werfen wir gemeinsam einen Blick darauf

Threads und Prozesse

1. Ein Thread teilt den Adressraum des Prozesses, der ihn erstellt hat. und der Prozess verfügt über einen eigenen Adressraum

2. Threads können auf alle Daten des Prozesses zugreifen, und Threads können auf einander zugreifen

3. Die Daten zwischen Threads sind unabhängig

4. Der untergeordnete Prozess kopiert die Daten des Threads

5. Der untergeordnete Prozess ist unabhängig, nachdem er gestartet wurde. Der übergeordnete Prozess kann den untergeordneten Prozess nur beenden, aber keine Daten austauschen >6. Ändern Sie die Daten im Thread. Alle wirken sich auf andere Threads aus, und Änderungen am Prozess wirken sich nicht auf den untergeordneten Prozess aus >

Thread ist ein Threading-Modul. Eine der wichtigsten Klassen in , mit der Sie Threads erstellen können. Es gibt zwei Möglichkeiten, einen Thread zu erstellen: Eine besteht darin, die Thread-Klasse zu erben und ihre Ausführungsmethode zu überschreiben. Die andere besteht darin, ein threading.Thread-Objekt zu erstellen und das aufrufbare Objekt als Parameter in seine Initialisierungsfunktion (__init__) einzugeben.

Sehen wir uns zunächst ein Beispiel für die Erstellung eines Threads durch Vererbung der Threading.Thread-Klasse an:

import threading
import time

class MyThread(threading.Thread):
 def __init__(self, arg):
  # super(MyThread, self).__init__() # 新式类继承原有方法写法
  threading.Thread.__init__(self)
  self.arg = arg

 def run(self):
  time.sleep(2)
  print(self.arg)

for i in range(10):
 thread = MyThread(i)
 print(thread.name)
 thread.start()

Eine andere Möglichkeit, einen Thread zu erstellen:


import threading
import time

def process(arg):
 time.sleep(2)
 print(arg)

for i in range(10):
 t = threading.Thread(target=process, args=(i,))
 print(t.name)
 t.start()

Die Thread-Klasse definiert außerdem die folgenden allgemeinen Methoden und Attribute:

Thread.getName() Get the Thread-Name

Thread.setName() Setzt den Thread-Namen

Thread.name Thread-Name

Thread.ident Den Bezeichner von abrufen der Thread. Die Thread-ID ist eine Ganzzahl ungleich Null. Dieses Attribut ist nur gültig, nachdem die start()-Methode aufgerufen wurde. Andernfalls wird nur None

zurückgegeben, um festzustellen, ob der Thread aktiv ist. Vom Zeitpunkt des Aufrufs der start()-Methode zum Starten des Threads bis zum Abschluss oder der Unterbrechung der run()-Methode aufgrund einer nicht behandelten Ausnahme ist der Thread aktiv


Thread.is_alive()

Thread. isAlive ()


Thread.join([timeout]) Der Aufruf von Thread.join blockiert den aufrufenden Thread, bis der aufgerufene Thread endet oder eine Zeitüberschreitung auftritt. Der Parameter timeout ist ein numerischer Typ, der die Timeout-Zeit angibt. Wenn dieser Parameter nicht angegeben wird, wird der aufrufende Hauptthread blockiert, bis der aufgerufene Thread endet

Python GIL (Global Interpreter Lock). )


GIL ist keine Funktion von Python, sondern ein Konzept, das bei der Implementierung des Python-Parsers (CPython) eingeführt wird. Genau wie C++ handelt es sich um eine Reihe von Sprachstandards (Grammatikstandards), die jedoch mit verschiedenen Compilern in ausführbaren Code kompiliert werden können. Berühmte Compiler wie GCC, INTEL C++, Visual C++ usw. Das Gleiche gilt für Python. Derselbe Code kann über verschiedene Python-Ausführungsumgebungen wie CPython, PyPy und Psyco ausgeführt werden. Beispielsweise verfügt JPython nicht über GIL. Da CPython jedoch in den meisten Umgebungen die Standardausführungsumgebung für Python ist. Daher ist CPython in der Vorstellung vieler Menschen Python und sie gehen davon aus, dass GIL ein Defekt der Python-Sprache ist. Lassen Sie uns hier klarstellen: GIL ist keine Funktion von Python und Python muss sich überhaupt nicht auf GIL verlassen.


Verwendung von Thread-Sperre:

# 锁:GIL 全局解释器 它是为了保证线程在运行过程中不被抢占
number = 0
lock = threading.RLock() # 创建锁


def run(num):
 lock.acquire() # 加锁
 global number
 number += 1
 print(number)
 time.sleep(2)
 lock.release() # 释放锁

for i in range(10):
 t = threading.Thread(target=run, args=(i, ))
 t.start()


Join & Daemon

Im Hauptthread A wird Unterthread B erstellt und B.setDaemon() im Hauptthread A aufgerufen. Dies bedeutet, dass Hauptthread A zu diesem Zeitpunkt als Daemon-Thread festgelegt ist endet, unabhängig davon, ob Sub-Thread B abgeschlossen ist, wird er mit Haupt-Thread A beendet. Dies ist die Bedeutung der setDaemon-Methode, die im Grunde das Gegenteil von Join ist. Darüber hinaus ist noch etwas Besonderes zu beachten: Sie muss vor dem Aufruf der start()-Methode festgelegt werden. Wenn sie nicht als Daemon-Thread festgelegt ist, wird das Programm auf unbestimmte Zeit angehalten.

class MyThread1(threading.Thread):
 def __init__(self):
  threading.Thread.__init__(self)

 def run(self):
  print("thread start")
  time.sleep(3)
  print('thread end')

print('main start')
thread1 = MyThread1()
# thread1.setDaemon(True)  # 设置子线程是否跟随主线程一起结束
thread1.start()
time.sleep(1)
print('satrt join')
# thread1.join() # 使主线程阻塞,直至子线程运行完毕再继续主线程
print('end join')


def run(n):
 print('[%s]------running----\n' % n)
 time.sleep(2)
 print('--done--')


def main():
 for i in range(5):
  t = threading.Thread(target=run, args=[i,])
  t.start()
  # t.join()
  print('starting thread', t.getName())


m = threading.Thread(target=main,args=[])
# m.setDaemon(True) # 将主线程设置为Daemon线程,它退出时,其它子线程会同时退出,不管是否执行完任务
m.start()
# m.join() # 使主线程阻塞,直至子线程运行完毕再继续主线程
print("---main thread done----")

Thread Lock (Mutex)

Mehrere Threads können unter einem Prozess gestartet werden, und mehrere Threads teilen sich den Speicherplatz des übergeordneten Prozesses, was bedeutet, dass jeder Thread zu diesem Zeitpunkt auf dieselben Daten zugreifen kann, wenn zwei Threads gleichzeitig dieselben Daten ändern möchten Zeit, was wird passieren?

num = 100 # 设定一个共享变量
def subNum():
 global num # 在每个线程中都获取这个全局变量
 print('--get num:', num)
 time.sleep(2)
 num -= 1 # 对此公共变量进行-1操作
thread_list = []
for i in range(100):
 t = threading.Thread(target=subNum)
 t.start()
 thread_list.append(t)
for t in thread_list: # 等待所有线程执行完毕
 t.join()
print('final num:', num)


# 加锁版本
def subNum():
 global num # 在每个线程中都获取这个全局变量
 print('--get num:', num)
 time.sleep(1)
 lock.acquire() # 修改数据前加锁
 num -= 1 # 对此公共变量进行-1操作
 lock.release() # 修改后释放

num = 100 # 设定一个共享变量
thread_list = []
lock = threading.Lock() # 生成全局锁
for i in range(100):
 t = threading.Thread(target=subNum)
 t.start()
 thread_list.append(t)
for t in thread_list: # 等待所有线程执行完毕
 t.join()
print('final num:', num)

Der Unterschied zwischen Rlock und Lock:

RLock ermöglicht die mehrfache Erfassung im selben Thread. Aber Lock lässt dies nicht zu. Andernfalls entsteht eine Endlosschleife und das Programm weiß nicht, welche Sperre aufgehoben werden soll. Hinweis: Wenn Sie RLock verwenden, müssen Acquire und Release paarweise erscheinen, d. h. nach dem Aufruf von Acquire n-mal muss Release n-mal aufgerufen werden, um die belegte Sperre wirklich freizugeben

Events


Python stellt das Event-Objekt für die Kommunikation zwischen Threads bereit. Es handelt sich um ein vom Thread gesetztes Signal-Flag, warten andere Threads, bis das Signal kontaktiert wird.

Das Event-Objekt implementiert einen einfachen Thread-Kommunikationsmechanismus. Es stellt Einstellungssignale, Löschsignale, Wartesignale usw. für die Kommunikation zwischen Threads bereit.

event = threading.Event() Ein Ereignis erstellen

1 Signal setzenevent.set()

Verwenden Sie die set()-Methode von Event, um das festzulegen Ereignisobjekt Das interne Signalflag ist wahr. Das Event-Objekt stellt die Methode isSet() bereit, um den Status seiner internen Signalflags zu bestimmen.

Wenn die set()-Methode des Ereignisobjekts verwendet wird, gibt die isSet()-Methode true zurück

2 Signal löschen

event.clear()

使用Event对象的clear()方法可以清除Event对象内部的信号标志,即将其设为假,当使用Event的clear方法后,isSet()方法返回假

3 等待
event.wait()

Event对象wait的方法只有在内部信号为真的时候才会很快的执行并完成返回。当Event对象的内部信号标志位假时,
则wait方法一直等待到其为真时才返回。也就是说必须set新号标志位真

def do(event):
 print('start')
 event.wait()
 print('execute')

event_obj = threading.Event()
for i in range(10):
 t = threading.Thread(target=do, args=(event_obj,))
 t.start()

event_obj.clear()
inp = input('输入内容:')
if inp == 'true':
 event_obj.set()

相关推荐:

Python多线程中阻塞(join)与锁(Lock)使用误区解析

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

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der einfachen Verwendung von Python-Multithreading, Sperren und Ereignismechanismen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
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