Heim > Artikel > Backend-Entwicklung > Lassen Sie uns über die gleichzeitige Programmierung in Go (1) sprechen.
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)
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. . . Schauen wir uns zuerst einen Fall an 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. 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 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. Werfen wir zunächst einen Blick auf den Unterschied zwischen Coroutinen und Threads. Coroutine kann verstanden werden als 线程大家应该都知道是可以被操作系统在任何时候进行切换,所以说线程就是抢占式多任务处理,线程是没有控制权,哪怕是一个语句执行到一半都会被操作系统切掉,然后转到其它线程去操作。 那么反之对于协程来说,什么时候交出控制权,什么时候不交出控制权是由协程内部主动决定的,正是因为这种非抢占式,所以被称之为轻量级。 并且 Im ersten Abschnitt haben wir gelernt, dass Sie viele Goroutinen in Go öffnen können. Der Zwei-Wege-Kanal zwischen Goroutinen ist dann Kanal 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. 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. 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. 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. Natürlich können Sie auch andere Parameter übergeben 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. 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. 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. 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. Quellcode 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 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. Aus dem obigen Code können Sie erkennen, dass Daten an den Kanal gesendet werden. Daher sollte der von der 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: 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的。 本小节源码 学习了这么久了,那么咔咔问你一个问题,这段代码执行会发生什么? 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. 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 passiert Eine Frage an Sie: Was passiert, wenn Sie Daten 4 an den Puffer senden? Du bist schlau, du musst über das Ergebnis nachgedacht haben, ja, es gemeldet Dann verwenden wir den vorherigen Arbeiter, um die Kanaldaten zu empfangen. 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. 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. Leihen Sie sich den Code aus dem vorherigen Fall aus, um mit der Erklärung fortzufahren. 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. 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. 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. Lightweight thread
, Nicht-präemptives Multitasking, die Coroutine übergibt aktiv die Kontrolle
. 轻量级的线程
,非抢占式多任务处理,由协程主动交出控制权
。多个协程是可以在一个或多个线程上运行的
Umgekehrt entscheidet die Coroutine aktiv, wann Kontrollrechte übergeben werden sollen und wann nicht. Gerade wegen dieses nichtpräventiven Stils wird dies als „Licht“ bezeichnet.
Mehrere Coroutinen können auf einem oder mehreren Threads ausgeführt werden
. 🎜🎜🎜🎜🎜🎜2Kann dieser Fall also bearbeitet werden? Kommen Sie und probieren Sie es aus
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,
createWorker
-Methode zurückgegebene Kanal mit createWorker
调用是报错了,Cannot use 'createWorker(i)' (type chanWenn Sie den Fehler sehen, sollten Sie wissen, dass die beiden Typen nicht gleichwertig sind.
package mainimport (
"fmt"
"time")func createWorker(id int) chan
deadlock
. deadlock
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.
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!