Heim  >  Artikel  >  So implementieren Sie die Parallelitätskontrolle in der Go-Sprache

So implementieren Sie die Parallelitätskontrolle in der Go-Sprache

DDD
DDDOriginal
2023-06-08 14:20:471836Durchsuche

Methoden zur Implementierung der Parallelitätskontrolle in der Go-Sprache: 1. WaitGroup, die Aufgabenverarbeitung mehrerer Goroutinen hat eine Abhängigkeits- oder Spleißbeziehung; 2. Kanal, Sie können die Arbeit von WaitGroup aktiv abbrechen; erfüllen die Funktionen von Kontext 3. Kontext, Signalausbreitung zwischen mehrstufigen Groutinen, einschließlich Metadatenausbreitung, Aufhebung der Signalausbreitung, Timeout-Kontrolle usw.

So implementieren Sie die Parallelitätskontrolle in der Go-Sprache

Die Betriebsumgebung dieses Artikels: Windows 10-System, go1.20-Version, Dell G3-Computer.

In Golang können Sie eine Goroutine über das Schlüsselwort go öffnen, sodass Sie problemlos gleichzeitigen Code in Go schreiben können. Aber wie kann man diese gleichzeitig ausgeführten Groutinen effektiv kontrollieren?

Bei der Parallelitätskontrolle denken viele Menschen vielleicht zuerst an Sperren. Golang bietet auch sperrbezogene Mechanismen, einschließlich Mutex-Sperre sync.Mutex und Lese-/Schreibsperre sync.RWMutex. Neben Sperren gibt es auch atomare Operationen sync/atomic usw. Der Fokus dieser Mechanismen liegt jedoch auf der gleichzeitigen Datensicherheit von Goroutinen. In diesem Artikel geht es um die Kontrolle des Parallelitätsverhaltens von Goroutine.

In der gleichzeitigen Verhaltenskontrolle von Goroutine gibt es drei gängige Methoden: WaitGroup, Channel und Context.

WaitGroup

WaitGroup befindet sich im Synchronisierungspaket und wird wie folgt verwendet.

func main() {
  var wg sync.WaitGroup

  wg.Add(2) //添加需要完成的工作量2

  go func() {
    wg.Done() //完成工作量1
    fmt.Println("goroutine 1 完成工作!")
  }()

  go func() {
    wg.Done() //完成工作量1
    fmt.Println("goroutine 2 完成工作!")
  }()

  wg.Wait() //等待工作量2均完成
  fmt.Println("所有的goroutine均已完成工作!")}输出:
//goroutine 2 完成工作!
//goroutine 1 完成工作!
//所有的goroutine均已完成工作!

WaitGroup Diese Parallelitätskontrollmethode eignet sich besonders für Situationen, in denen eine bestimmte Aufgabe die Zusammenarbeit mehrerer Goroutinen erfordert und jede Goroutine nur einen Teil der Aufgabe erledigen kann. Die Aufgabe wird erst abgeschlossen, wenn alle Goroutinen abgeschlossen sind. Daher hat WaitGroup dieselbe Bedeutung wie sein Name, nämlich eine Art des Wartens.

Im tatsächlichen Geschäftsleben gibt es jedoch ein Szenario: Wenn eine bestimmte Anforderung erfüllt ist, muss eine bestimmte Goroutine aktiv benachrichtigt werden, um beendet zu werden. Wenn wir beispielsweise eine Hintergrundüberwachungs-Goroutine starten und die Überwachung nicht mehr benötigt wird, sollten wir die Überwachungs-Goroutine über das Ende informieren, da sie sonst im Leerlauf bleibt und Lecks verursacht.

Channel

Für das obige Szenario ist WaitGroup machtlos. Die einfachste Methode, die man sich vorstellen kann, besteht darin, eine globale Variable zu definieren und sie durch Ändern dieser Variablen an anderer Stelle zu benachrichtigen. Wenn sie feststellt, dass sich die Variable geändert hat, wird diese Methode geschlossen ist etwas umständlich. In diesem Fall kann Kanal+Auswahl hilfreich sein.

func main() {
  exit := make(chan bool)

  go func() {
    for {
      select {
      case <-exit:
        fmt.Println("退出监控")
        return
      default:
        fmt.Println("监控中")
        time.Sleep(2 * time.Second)
      }
    }
  }()

  time.Sleep(5 * time.Second)
  fmt.Println("通知监控退出")
  exit <- true

  //防止main goroutine过早退出
  time.Sleep(5 * time.Second)}输出:
//监控中
//监控中
//监控中
//通知监控退出
//退出监控

Diese Kombination aus Kanal+Auswahl ist eine elegantere Möglichkeit, die Goroutine über das Ende zu informieren.

Diese Lösung weist jedoch auch Einschränkungen auf. Stellen Sie sich vor, was wäre, wenn es mehrere Goroutinen gäbe, die alle kontrolliert werden müssten, um zu beenden? Was wäre, wenn diese Goroutinen andere Goroutinen hervorbringen würden? Natürlich können wir viele Kanäle definieren, um dieses Problem zu lösen, aber die Beziehungskette von Goroutinen führt zur Komplexität dieses Szenarios.

Kontext

Die oben genannten Szenarien sind im CS-Architekturmodell üblich. In Go wird oft eine separate Goroutine (A) für jeden Client geöffnet, um seine Reihe von Anfragen zu bearbeiten, und oft fordert ein einzelner A auch andere Dienste an (startet eine andere Goroutine B), und B kann auch eine andere Goroutine C, C anfordern Anschließend wird die Anfrage an einen Server wie Databse gesendet. Stellen Sie sich vor, dass, wenn der Client die Verbindung trennt, A, B und C, die ihm zugeordnet sind, sofort beendet werden müssen, bevor das System die von A, B und C belegten Ressourcen zurückgewinnen kann. Das Verlassen von A ist einfach, aber wie kann man B und C benachrichtigen, dass sie ebenfalls verlassen sollen?

Zu diesem Zeitpunkt erscheint Kontext.

func A(ctx context.Context, name string)  {
  go B(ctx ,name) //A调用了B  for {
    select {
    case <-ctx.Done():
      fmt.Println(name, "A退出")
      return
    default:
      fmt.Println(name, "A do something")
      time.Sleep(2 * time.Second)
    }
  }}func B(ctx context.Context, name string)  {
  for {
    select {
    case <-ctx.Done():
      fmt.Println(name, "B退出")
      return
    default:
      fmt.Println(name, "B do something")
      time.Sleep(2 * time.Second)
    }
  }}func main() {
  ctx, cancel := context.WithCancel(context.Background())

  go A(ctx, "【请求1】") //模拟client来了1个连接请求

  time.Sleep(3 * time.Second)
  fmt.Println("client断开连接,通知对应处理client请求的A,B退出")
  cancel() //假设满足某条件client断开了连接,那么就传播取消信号,ctx.Done()中得到取消信号

  time.Sleep(3 * time.Second)}输出:
//【请求1】 A do something
//【请求1】 B do something
//【请求1】 A do something
//【请求1】 B do something
//client断开连接,通知对应处理client请求的A,B退出
//【请求1】 B退出
//【请求1】 A退出

Im Beispiel wird eine Verbindungsanfrage vom Client simuliert und Goroutine A wird entsprechend für die Verarbeitung von A geöffnet. Sowohl A als auch B verwenden den Kontext zur Nachverfolgung , diese beiden Alle Goroutinen werden beendet.

Dies ist die Kontrollfunktion von Context. Nach dem Drücken des Schalters erhalten alle auf diesem Kontext basierenden oder davon abgeleiteten Unterkontexte Benachrichtigungen endlich veröffentlicht Dies löst auf elegante Weise das Problem der unkontrollierbaren Goroutine nach dem Start.

Die detaillierte Verwendung von Kontext würde den Rahmen dieses Artikels sprengen. Es wird einen Folgeartikel geben, in dem das Kontextpaket speziell erläutert wird. Bleiben Sie also auf dem Laufenden.

Zusammenfassung

In diesem Artikel werden drei Modi zur Steuerung des Parallelitätsverhaltens in Golang aufgeführt. Es gibt keine gute oder schlechte Unterscheidung zwischen den Modi, es kommt lediglich darauf an, geeignete Lösungen für verschiedene Szenarien zu verwenden. In tatsächlichen Projekten werden häufig mehrere Methoden kombiniert verwendet.

  • WaitGroup: Es besteht eine Abhängigkeit oder Spleißbeziehung zwischen der Aufgabenverarbeitung mehrerer Goroutinen.
  • channel+select: Sie können Goroutine aktiv abbrechen; die Datenübertragung in mehreren Groutinen kann die Arbeit von WaitGroup ersetzen, aber es erhöht die Komplexität der Codelogik, kann aber auch den Code erfüllen Logikkomplex.
  • Kontext: Signalausbreitung zwischen mehrstufigen Groutinen (einschließlich Metadatenausbreitung, Aufhebung der Signalausbreitung, Timeout-Kontrolle usw.).

In Golang können Sie eine Goroutine über das Schlüsselwort go öffnen, sodass Sie problemlos gleichzeitigen Code in Go schreiben können. Aber wie kann man diese gleichzeitig ausgeführten Groutinen effektiv kontrollieren?

Wenn es um Parallelitätskontrolle geht, denken viele Menschen vielleicht zuerst an Sperren. Golang bietet auch sperrbezogene Mechanismen, einschließlich Mutex-Sperre sync.Mutex und Lese-/Schreibsperre sync.RWMutex. Neben Sperren gibt es auch atomare Operationen sync/atomic usw. Der Fokus dieser Mechanismen liegt jedoch auf der gleichzeitigen Datensicherheit von Goroutinen. In diesem Artikel geht es um die Kontrolle des Parallelitätsverhaltens von Goroutine.

In der gleichzeitigen Verhaltenskontrolle von Goroutine gibt es drei gängige Methoden: WaitGroup, Channel und Context.

Das obige ist der detaillierte Inhalt vonSo implementieren Sie die Parallelitätskontrolle in der Go-Sprache. 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