Heim  >  Artikel  >  Backend-Entwicklung  >  Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

咔咔
咔咔Original
2021-07-07 16:13:502161Durchsuche

Lassen Sie uns über Gos Goroutine und Channel sprechen

Grundlegende Verwendung
  • will Kanal wird als Parameter übergeben
  • Mehrere Kanäle erstellen
    • Kanal als Rückgabewert verwenden
    • Pufferkanal
    • Kanal ist geschlossen
  • Empfohlene verwandte Artikel: „
      Sprechen Sie über gleichzeitige Programmierung in Go ( 2)
    • "
    • Vorwort

    Als ich zuvor die Go-Sprache gelernt habe, habe ich sie übersprungen, als ich Groutine und Channel sah. Ich habe es damals überhaupt nicht ernst genommen, warum denkst du, dass es so kompliziert ist? (Mein damaliger Geisteszustand)

    Kürzlich habe ich mir die gleichzeitige Programmierung in Go angesehen und festgestellt, dass es nur um diesen Teil des Inhalts geht, also musste ich in den sauren Apfel beißen, aber Sie werden feststellen, dass es so ist ist nach dem Anschauen gar nicht so schwer.

    Manchmal können Sie Dinge wegräumen, die Sie nicht sehen möchten, und sie dann überprüfen, nachdem Sie Ihre Aufmerksamkeit konzentriert haben. Sie werden unerwartete Gewinne erzielen.

    Der heutige Artikel ist eine einfache Erklärung. Ich habe mich auch für einen Go-Kurs angemeldet. Ich werde sehen, ob ich in welchem ​​​​Kurs mehr Verständnis erlangen kann, und dann werde ich ausführliche Ergänzungen vornehmen. 1. Goroutine Es gibt viele Punkte zum Wechseln. Dies ist nur eine Referenz. Es gibt keine Garantie dafür, dass es nicht an anderen Stellen gewechselt wird. E/A-Operationen, Kanäle, Warten auf Sperren, Funktionsaufrufe, runtime.Gosched() usw. . .

    Verwenden Sie Race, um Datenzugriffskonflikte zu erkennen

    Lesen Sie zuerst den Fall, um zu erfahren, wie man Goroutine verwendet

    Schauen wir uns zuerst einen Fall an

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Dieser Fall ist ein einfacher gleichzeitiger Ausführungscode, der nur das Schlüsselwort go in go ist.

    Schauen wir uns also an, was dieser Code ausgibt. Auf dem Bild oben können Sie sehen, dass diese Codezeile nichts ausgibt und direkt beendet wird.

    Der Grund, warum wir direkt beenden, liegt darin, dass der Haupt- und der FMT-Druck in unserem Code gleichzeitig ausgeführt werden. Wenn FMT Daten dringend druckt, bevor sie eintreffen, ist die äußere Schleife bereits beendet und wird dann direkt beendet. Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    In der Go-Sprache! Nehmen Sie an, dass nach dem Beenden einer Hauptfunktion alle Goroutinen direkt beendet werden, sodass das Phänomen besteht, dass die dringenden Druckdaten zurückgegeben werden, bevor die Goroutine kommt.

    Sie fragen sich also, wie Sie die gedruckten Daten sehen können? Tatsächlich ist es ganz einfach: Beenden Sie den Vorgang einfach nicht so schnell, nachdem die Hauptfunktion ausgeführt wurde, und geben Sie ihr etwas Zeit zum Warten. Schauen Sie sich den Fall an

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Das gewünschte Ergebnis wird dieses Mal angezeigt.

    In diesem Fall beträgt die Anzahl der geöffneten Goroutinen 10. Was passiert also, wenn sie auf 1000 geändert wird?

    Die Ergebnisse werden immer noch normal angezeigt, so als würden 1.000 Menschen gleichzeitig Dinge drucken.

    Was hat also Einstellung 10 mit 1000 zu tun?

    Wer mit dem Betriebssystem vertraut ist, sollte wissen, dass es kein Problem ist, 10 Threads zu öffnen, und dass es kein großes Problem ist, 100 Threads zu öffnen, aber es ist fast genug.

    Im Allgemeinen reicht es aus, Dutzende Threads im System zu öffnen. Wenn jedoch 1.000 Personen gleichzeitig eine Aufgabe erledigen müssen, können Threads nicht zur Lösung des Problems verwendet werden und es ist eine asynchrone Methode erforderlich.

    Aber in Go-Sprache! Verwenden Sie einfach das Schlüsselwort go direkt und es kann gleichzeitig ausgeführt werden.

    Lassen Sie uns als Nächstes darüber sprechen, warum go 1000 Personen gleichzeitig drucken kann.

    Was ist

    Werfen wir zunächst einen Blick auf den Unterschied zwischen Coroutinen und Threads.

    Coroutine kann verstanden werden als Lightweight thread, Nicht-präemptives Multitasking, die Coroutine übergibt aktiv die Kontrolle. 轻量级的线程非抢占式多任务处理,由协程主动交出控制权

    线程大家应该都知道是可以被操作系统在任何时候进行切换,所以说线程就是抢占式多任务处理,线程是没有控制权,哪怕是一个语句执行到一半都会被操作系统切掉,然后转到其它线程去操作。

    那么反之对于协程来说,什么时候交出控制权,什么时候不交出控制权是由协程内部主动决定的,正是因为这种非抢占式,所以被称之为轻量级。

    并且多个协程是可以在一个或多个线程上运行的

    Jeder sollte wissen, dass Threads jederzeit vom Betriebssystem gewechselt werden können, sodass Threads keine Kontrolle haben. Auch wenn eine Anweisung auf halbem Weg ausgeführt wird, wird sie dann abgeschnitten Gehen Sie zu anderen Threads, um zu arbeiten.

    Umgekehrt entscheidet die Coroutine aktiv, wann Kontrollrechte übergeben werden sollen und wann nicht. Gerade wegen dieses nichtpräventiven Stils wird dies als „Licht“ bezeichnet.
    🎜🎜🎜andMehrere Coroutinen können auf einem oder mehreren Threads ausgeführt werden. 🎜🎜🎜🎜🎜🎜2

    Im ersten Abschnitt haben wir gelernt, dass Sie viele Goroutinen in Go öffnen können. Der Zwei-Wege-Kanal zwischen Goroutinen ist dann Kanal

    Wie Sie im obigen Fall sehen können, können Sie die Make-Funktion direkt verwenden, um einen Kanal zu erstellen.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Die siebte und achte Zeile dienen dazu, Daten an den Kanal zu senden.

    Kann dieser Fall also bearbeitet werden? Kommen Sie und probieren Sie es aus

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Sie können sehen, dass zu diesem Zeitpunkt ein Fehler gemeldet wurde. Der Fehler bedeutet, dass beim Senden von 1 an den Kanal ein Deadlock auftritt.

    Dann gehe zurück zum vorherigen Bild.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Wie wir oben gesagt haben, ist Kanal eine Interaktion zwischen Goroutine und Goroutine.

    Aber in diesem Fall gibt es nur eine Goroutine, daher ist eine andere Goroutine erforderlich, um sie zu empfangen.

    Jetzt solltest du wissen, wie man eine Goroutine startet.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Im Bild oben haben wir eine weitere Goroutine neu geöffnet und dann eine Endlosschleife verwendet, um den vom Kanal gesendeten Wert zu empfangen und auszudrucken.

    Aber Sie werden feststellen, dass wir zwei Daten an den Kanal gesendet haben, das Druckergebnis zu diesem Zeitpunkt jedoch nur ein Datenelement enthält. Aber es ist besser als das, womit wir angefangen haben, richtig!

    Warum passiert das?

    Sie können den Ausführungsprozess des Codes verstehen. Zuerst wird eine 1 an den Kanal gesendet und dann der erste Wert in einer Schleife abgerufen und gedruckt.

    Daten 2 erneut an den Kanal senden, aber direkt vor dem Drucken beenden, was zu dem Phänomen führt, dass nur Daten 1 angezeigt werden, nicht jedoch Daten 2.

    Durch Kakas Beschreibung sollten Sie bereits wissen, wie Sie dieses Problem lösen können.

    Das heißt, der Funktion „channelDome“ eine verzögerte Ausgangszeit hinzuzufügen.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Kanal als Parameter übergeben

    Wie Sie oben sehen können, folgt auf go eine Abschlussfunktion, und das in diesem Abschluss verwendete c ist die äußere Schicht, die c verwendet wird.

    Ist es also möglich, dieses c mithilfe von Parametern zu übergeben? Die Antwort ist ja.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Natürlich können Sie auch andere Parameter übergeben

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Sie können dem obigen Bild entnehmen, dass nicht nur der Kanal, sondern auch der ID-Parameter übergeben wird. Gleichzeitig kann der Code auch direkt in den eingeschlossenen Teil, also den Wert, optimiert werden direkt vom Kanal übernommen.

    Erstellen Sie mehrere Kanäle

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Wie Sie auf dem Bild oben sehen können, hat jeder seinen eigenen Kanal und verteilt ihn dann. Nach der Verteilung erhält jeder seinen eigenen erhaltenen Wert und Druck es raus.

    Ähnlich können Sie sehen, dass wir in Zeile 26 eine neue for-Schleife hinzugefügt haben, um Daten an den Kanal zu senden.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Aus den laufenden Ergebnissen werden Sie feststellen, dass die Druckreihenfolge verwirrend ist, z. B. die beiden Werte „receive i“ und „receive I“.

    Haben Sie an dieser Stelle irgendwelche Zweifel? Wenn wir Daten an den Kanal senden, senden wir sie der Reihe nach! Dann müssen sie beim Empfang in der richtigen Reihenfolge empfangen werden.

    Da wir sehr sicher sind, dass die Daten in der richtigen Reihenfolge gesendet werden, kann das Problem nur bei Printf auftreten.

    Da Printf über E/A verfügt und von Goroutine geplant wird, ist Printf zu diesem Zeitpunkt außer Betrieb, aber die empfangenen Werte werden einzeln ausgedruckt.

    Kanal als Rückgabewert verwenden

    Die Fälle in den vorherigen Abschnitten wurden alle von Kanal erstellt und dann als Parameter übergeben.

    Dann gibt dieser Abschnitt den Kanal als Rückgabewert zurück.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Quellcode

    package mainimport (
    	"fmt"
    	"time")func createWorker(id int) chan int {
    	c := make(chan int)
    	go func() {
    		for {
    			fmt.Printf("Worker %d receive %c\n", id, 

    Von hier aus können Sie sehen, dass wir die Worker-Funktion in die createWorker-Funktion geändert haben, da in dieser Funktion der Kanal direkt erstellt wird.

    Dann wird der vom Kanal empfangene Wert über eine Coroutine gedruckt.

    Den Kanal zurückgeben.

    Werfen wir einen Blick auf die Laufergebnisse

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Aus den laufenden Ergebnissen können Sie erkennen, dass unser Codeschreiben immer noch korrekt ist, aber Sie können sehen, wie Sie den zu diesem Zeitpunkt zurückgegebenen Kanal sehr intuitiv verwenden können.

    Aber wenn es viele Codes gibt, wissen Sie es nicht Wie man diesen Kanal überhaupt nutzt, dieser gesamte Code muss einfach geändert werden.

    Dann muss man den Leuten draußen sagen, wie man es benutzt.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Aus dem obigen Code können Sie erkennen, dass Daten an den Kanal gesendet werden. Daher sollte der von der createWorker-Methode zurückgegebene Kanal mit

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    markiert sein

    Der aktuelle Code sieht also so aus. Wir markieren direkt die Richtung des Rückgabewertkanals der createWorker-Methode. Die Funktion besteht darin, Daten zu senden.

    Beim Drucken ist es dann der Beleg, der sehr intuitiv aussieht.

    Nachdem Sie die beiden oben genannten Schritte geändert haben, werden Sie feststellen: createWorker调用是报错了,Cannot use 'createWorker(i)' (type chanWenn Sie den Fehler sehen, sollten Sie wissen, dass die beiden Typen nicht gleichwertig sind.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Nach der Änderung werden Sie feststellen, dass die Kompilierung korrekt ist und keine Fehlermeldung gemeldet wird.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.也是ok的。

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    本小节源码

    package mainimport (
    	"fmt"
    	"time")func createWorker(id int) chan

    buffer channel

    学习了这么久了,那么咔咔问你一个问题,这段代码执行会发生什么?

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Ja, es wird ein Fehler auftreten, denn wie am Anfang des Artikels erwähnt, müssen Sie zum Senden von Daten an einen Kanal eine andere Coroutine öffnen, um die Daten zu empfangen.

    Obwohl Coroutinen als leichtgewichtig gelten, müssen Sie nach dem Senden von Daten die Coroutinen wechseln, um Daten zu empfangen, was sehr ressourcenintensiv ist.

    Dann erkläre ich dir das in diesem Abschnitt.

    buffer channel

    Erstellen Sie einen Kanal, der 3 Puffer haben kann, und senden Sie dann 3 Daten an den Kanal.

    An den Ergebnissen des gleichzeitigen Laufens können Sie auch erkennen, dass es nicht passiertdeadlock.

    Eine Frage an Sie: Was passiert, wenn Sie Daten 4 an den Puffer senden?

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Du bist schlau, du musst über das Ergebnis nachgedacht haben, ja, es gemeldetdeadlock

    Dann verwenden wir den vorherigen Arbeiter, um die Kanaldaten zu empfangen.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Aber Sie werden feststellen, dass das laufende Ergebnis die eingesandten 1,2,3,4 immer noch nicht ausdruckt.

    Diese Frage wurde jetzt schon mehrmals gestellt. Sie können versuchen, sich zu fragen, wie Sie diese Situation lösen sollten.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Fügen Sie einfach eine Verzögerungszeit hinzu. Lassen Sie mich Ihnen übrigens erklären, dass im vorherigen Fall Buchstaben und alle Formatierungen %c gedruckt wurden, jetzt werden Zahlen gedruckt, also ändern Sie Für %d, eine kleine Änderung .

    Die Einrichtung von Kanälen auf diese Weise hat einen gewissen Effekt auf die Leistungssteigerung.

    Haben Sie bisher ein Problem festgestellt, das heißt, Sie wissen nicht, wann der Kanal versendet wurde?

    Schauen wir uns als nächstes dieses Problem an.

    Kanal geschlossen

    Leihen Sie sich den Code aus dem vorherigen Fall aus, um mit der Erklärung fortzufahren.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.
    Was mit dem vorherigen Code nicht übereinstimmt, ist, dass wir am Ende „close“ hinzugefügt haben. Es ist zu beachten, dass „close“ für den Absender geschlossen ist.

    Sie werden sehen, dass die Laufergebnisse nicht zufriedenstellend sind. Sie werden feststellen, dass 1,2,3,4 eingegangen sind.

    Aber unten wurden viele Nullen empfangen, aber der Screenshot erfasste nur ein Datenelement.

    Obwohl der Absender den Kanal schließt, empfängt der Arbeiter weiterhin die Daten, wenn der Kanal geschlossen wird. Dies bedeutet nicht, dass die Daten nach dem Schließen des Kanals nicht empfangen werden.

    Aber wenn der Absender den Kanal auf „Schließen“ setzt, sind die empfangenen Daten alle 0, dh der Wert des von der Worker-Methode übergebenen Parameters c chan int ist 0.

    Jetzt ist unser Kanal vom Typ int und wir haben 0 erhalten. Wenn es sich dann um einen String-Typ handelt, wird ein leerer String empfangen.

    Wie lange wird das dauern? Das ist die von uns festgelegte Zeit von einer Millisekunde.

    Wenn Sie gebeten wurden, dieses Programm zu ändern, haben Sie irgendwelche Ideen? Wenn Sie keine Ahnung haben, wiegen Sie einfach mit diesem Rhythmus.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Im Funktionsarbeiter werden zwei Werte zum Empfangen verwendet, n ist der übergebene Kanal c. ok dient dazu, festzustellen, ob der Wert vorhanden ist.

    Sie können die laufenden Ergebnisse sehen und erhalten keine 0 Daten mehr.

    Zusätzlich zu dieser Schreibweise gibt es noch eine einfachere Möglichkeit.

    Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.

    Beharrlichkeit beim Lernen, Beharrlichkeit beim Schreiben und Beharrlichkeit beim Teilen sind die Überzeugungen, an denen Kaka seit seinen Anfängen festgehalten hat. Ich hoffe, dass Kakas Artikel im riesigen Internet Ihnen ein wenig helfen können. Ich bin Kaka, bis zum nächsten Mal.

Das obige ist der detaillierte Inhalt vonLassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.. 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