Technologieaustausch

Go-Sprache --- gleichzeitiger Programmierkanal (Dual Channel, Single Channel) und Anwendungsbeispiele (Producer Consumer, Druckermodell)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Kanal

Goroutinen laufen im selben Adressraum, daher muss der Zugriff auf den gemeinsam genutzten Speicher synchronisiert werden.Goroutinen teilen den Speicher durch Kommunikation, anstatt den Speicher zu teilen.

Der Referenztypkanal ist eine spezifische Implementierung des CSP-Modus und wird für die Kommunikation mehrerer Goroutinen verwendet. Es implementiert die Synchronisierung intern, um die Sicherheit der Parallelität zu gewährleisten.

Kanaltyp

Wie Map ist auch Channel ein Verweis auf die zugrunde liegende Datenstruktur, die von make erstellt wurde.
Wenn wir einen Kanal kopieren oder ihn für die Übergabe von Funktionsparametern verwenden, kopieren wir einfach eine Kanalreferenz, sodass der Aufrufer und der Angerufene auf dasselbe Kanalobjekt verweisen. Wie bei anderen Referenztypen ist der Nullwert des Kanals Null.
Wenn Sie einen Kanal definieren, müssen Sie auch die Art der an den Kanal gesendeten Werte definieren. Kanäle können mit der integrierten Funktion make() erstellt werden:

make (chan Type)
make (chan Type,capacity)
  • 1
  • 2
  • Bei Kapazität=0 ist der Kanal ungepuffert und blockiert Lese- und Schreibvorgänge. Bei Kapazität>0 verfügt der Kanal über einen Cache und ist nicht blockierend. Das Schreiben wird nicht blockiert, bis die Kapazitätselemente gefüllt sind.
  • Chamnel empfängt und sendet Daten über den Operator <-. Die Syntax zum Senden und Empfangen von Daten lautet:
channel<-value   //发送value 到channel
<-channel     //接收并将其丢弃
x:=<-channel   //从 channel 中接收数据,并賦偵给x
x,ok:=<-channel   //功能同上,同时检查通道是否已关闭或者是否为空
  • 1
  • 2
  • 3
  • 4

Standardmäßig blockiert der Kanal das Empfangen und Senden von Daten, es sei denn, das andere Ende ist bereit, wodurch die Goroutine-Synchronisierung einfacher wird, ohne dass explizite Sperren erforderlich sind.

erreichen

Fügen Sie hier eine Bildbeschreibung ein

  • Die Rohre werden jeweils eine vor dem Druck und eine hinter dem Druck platziert.
  • Wenn Person2 zuerst ausgeführt wird und sich keine Daten in der Pipeline befinden, wird es blockiert.
  • Person1 führt die Daten aus und gibt sie nach dem Drucken in die Pipe ein. Person2 erkennt sie und beginnt mit dem Drucken.

Implementieren Sie Synchronisierung und Dateninteraktion über Kanäle

Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein

ungepufferter Kanal

Ein ungepufferter Kanal ist ein Kanal, der vor dem Empfang keinen Wert speichern kann.
Diese Art von Kanal erfordert, dass die sendende Goroutine und die empfangende Goroutine gleichzeitig bereit sind, die Sende- und Empfangsvorgänge abzuschließen. Wenn zwei Goroutinen nicht gleichzeitig bereit sind, bewirkt der Kanal, dass die Goroutine, die zuerst den Sende- oder Empfangsvorgang ausführt, blockiert und wartet.
Dieses Zusammenspiel von Senden und Empfangen an den Kanal ist von Natur aus synchron. Keine Operation kann unabhängig von der anderen existieren.
Die folgende Abbildung zeigt, wie zwei Goroutinen mithilfe ungepufferter Kanäle einen Wert gemeinsam nutzen können:
Fügen Sie hier eine Bildbeschreibung ein

  • Das heißt, der Kanal selbst kann keine Dinge speichern. Wenn Sie etwas hineinstecken, können Sie es sofort herausnehmen.
  • In Schritt 1 treffen beide Goroutinen auf dem Kanal ein, aber keine beginnt mit dem Senden oder Empfangen.
  • In Schritt 2 streckt die Goroutine auf der linken Seite ihre Hand in den Kanal und simuliert so den Vorgang des Sendens von Daten an den Kanal. Zu diesem Zeitpunkt bleibt die Goroutine im Kanal gesperrt, bis der Austausch abgeschlossen ist.
  • In Schritt 3 legt die Goroutine auf der rechten Seite ihre Hand in den Kanal, wodurch der Empfang von Daten vom Kanal simuliert wird. Auch diese Goroutine bleibt im Kanal gesperrt, bis der Austausch abgeschlossen ist.
  • In den Schritten 4 und 5 findet ein Austausch statt, und schließlich nehmen in Schritt 6 beide Goroutinen ihre Hände aus dem Kanal, was die Freigabe der gesperrten Goroutine simuliert. Beide Goroutinen können nun andere Dinge tun.

Erstellen Sie einen ungepufferten Kanal

make (chan Type)//等价于make (chan Type,0)
  • 1

Wenn keine Puffergröße angegeben ist, ist der Kanal synchron und blockiert daher, bis der Sender sendebereit und der Empfänger empfangsbereit ist.

Fügen Sie hier eine Bildbeschreibung ein

  • ch&lt;-i schreibt Daten nicht in den Kanal, bis es sie erkennt. Zu diesem Zeitpunkt wird auch die Sub-Coroutine blockiert und wartet, bis die Sub-Coroutine fortfährt.
  • println druckt jedoch Daten, nachdem die Pipe gelesen wurde, sodass die Druckgeschwindigkeit vom System bestimmt wird.

gepufferter Kanal

Ein gepufferter Kanal ist ein Kanal, der vor dem Empfang einen oder mehrere Werte speichern kann.
Für diese Art von Kanal ist es nicht erforderlich, dass die Goroutine gleichzeitig das Senden und Empfangen abschließt. Für Kanäle gelten außerdem unterschiedliche Bedingungen, die Sende- und Empfangsaktionen blockieren. Die Empfangsaktion wird nur blockiert, wenn im zu empfangenden Kanal kein Wert vorhanden ist. Die Sendeaktion wird nur blockiert, wenn der Kanal keinen verfügbaren Puffer für den gesendeten Wert hat.
Dies führt zu einem großen Unterschied zwischen gepufferten und ungepufferten Kanälen: Ungepufferte Kanäle garantieren, dass sendende und empfangende Goroutinen gleichzeitig Daten austauschen; gepufferte Kanäle haben keine solche Garantie.
Fügen Sie hier eine Bildbeschreibung ein

  • In Schritt 1 empfängt die Goroutine auf der rechten Seite einen Wert vom Kanal.
  • In Schritt 2 schließt die Goroutine auf der rechten Seite den Vorgang des unabhängigen Empfangens des Werts ab, während die Goroutine auf der linken Seite einen neuen Wert an den Kanal sendet.
  • In Schritt 3 sendet die Goroutine auf der linken Seite immer noch einen neuen Wert an den Kanal, während die Goroutine auf der rechten Seite einen anderen Wert vom Kanal empfängt. Die beiden Vorgänge in diesem Schritt sind weder synchronisiert noch blockieren sie sich gegenseitig.
  • Schließlich ist in Schritt 4 das gesamte Senden und Empfangen abgeschlossen, und es sind noch einige Werte im Kanal und etwas Platz zum Speichern weiterer Werte vorhanden.

erstellen

make (chan Type,capacity)
  • 1

Wenn eine Pufferkapazität angegeben ist, ist der Kanal asynchron. Solange der Puffer ungenutzten Platz zum Senden von Daten hat oder empfangbare Daten enthält, läuft die Kommunikation ohne Blockierung weiter.

erreichen

Fügen Sie hier eine Bildbeschreibung ein

  • Wenn genügend drei gespeichert sind, wird es blockiert und auf das Lesen gewartet. Wenn die Haupt-Coroutine ein Datenelement gelesen hat und freier Speicherplatz vorhanden ist, wird die Unter-Coroutine weiter ausgeführt und die nachfolgende Druckreihenfolge ist nicht sicher.
    Fügen Sie hier eine Bildbeschreibung ein

Kanal schließen

Mit ok kann der Kanal erkennen, ob der Kanal noch geöffnet ist. Wenn der Kanal geschlossen ist, werden die Daten nicht gelesen.

Fügen Sie hier eine Bildbeschreibung ein

  • num ,ok:=<-chKann erkennen, ob ein Kanal geschlossen ist.

Beachten

  • Kanäle müssen nicht so oft geschlossen werden wie Dateien. Schließen Sie den Kanal nur, wenn Sie wirklich keine Daten zum Senden haben oder wenn Sie die Bereichsschleife oder ähnliches explizit beenden möchten.
  • Nach dem Schließen des Kanals können keine Daten mehr an den Kanal gesendet werden (es wird ein Panikfehler ausgelöst, der dazu führt, dass der Empfang sofort einen Nullwert zurückgibt):
  • Nach dem Schließen des Kanals können Sie weiterhin Daten vom Kanal empfangen:
  • Bei Nullkanälen werden sowohl das Senden als auch das Empfangen blockiert.
    Fügen Sie hier eine Bildbeschreibung ein
  • Mithilfe der Reichweite können Sie den Kanal durchqueren und automatisch aus der Schleife springen
    Fügen Sie hier eine Bildbeschreibung ein

Einwegkanal

Standardmäßig ist der Kanal ein Dual-Quest-Kanal, d. h. Sie können Daten an ihn senden und Daten von ihm empfangen.
Allerdings sehen wir oft, dass ein Kanal als Parameter übergeben wird und der Wert voraussichtlich nur in eine Richtung verwendet wird, entweder nur zum Senden von Daten oder nur zum Empfangen von Daten. Zu diesem Zeitpunkt können wir die Richtung des Kanals angeben. Die Deklaration einer Einweg-Chamel-Variable ist wie folgt sehr einfach:

var ch1 chan int //ch1双向
var ch2 chan<-float64 //ch2单向,只能用于写float64数据
var ch3 <-chan int  //ch3单向,只能用于读int数据
  • 1
  • 2
  • 3

chan&lt;- bedeutet, dass Daten in die Pipe eingegeben werden und die Daten in die Pipe geschrieben und an den Aufrufer ausgegeben werden.
&lt;-chan zeigt an, dass die Daten aus der Pipe kommen. Für den Anrufer werden die Daten aus der Pipe abgerufen, was natürlich die Eingabe ist.
Ein Kanal kann implizit in eine unidirektionale Warteschlange umgewandelt werden, die nur empfängt oder nur sendet, aber ein unidirektionaler Kanal kann nicht in einen normalen Kanal umgewandelt werden;

Fügen Sie hier eine Bildbeschreibung ein

Nutzen Sie einen einzigen Kanal, um das Produzenten-Konsumenten-Modell umzusetzen

Fügen Sie hier eine Bildbeschreibung ein