Heim  >  Artikel  >  php教程  >  Detaillierte Erläuterung der Kommunikation zwischen PHP und der Go-Sprache

Detaillierte Erläuterung der Kommunikation zwischen PHP und der Go-Sprache

高洛峰
高洛峰Original
2016-12-28 15:50:412363Durchsuche

Vorwort

Ein Szenario, auf das ich kürzlich bei der Arbeit gestoßen bin, war, dass eine Funktion eines Drittanbieters im PHP-Projekt verwendet werden musste und es zufällig eine in Golang geschriebene Klassenbibliothek gab. Es stellt sich also die Frage, wie eine Kommunikation zwischen verschiedenen Sprachen erreicht werden kann. Schauen wir uns unten um.

Konventionelle Lösung

1. Verwenden Sie Golang, um einen http/TCP-Dienst zu schreiben, und PHP kommuniziert mit Golang über http/TCP

2. Führen Sie Golang durch mehr Als PHP-Erweiterung gekapselt.

3. PHP ruft die ausführbare Golang-Datei über Systembefehle auf

Probleme

1. HTTP-Anfrage, Netzwerk-E/A wird verbraucht viel Zeit

2. Eine große Menge Code muss gekapselt werden

3. Jedes Mal, wenn PHP ein Golang-Programm aufruft, muss es initialisiert werden, was viel Zeit in Anspruch nimmt viel Zeit

Optimierungsziele

1. Das Golang-Programm wird nur einmal initialisiert (da die Initialisierung zeitaufwändig ist)

2. Alle Anfragen müssen nicht über das Netzwerk erfolgen

3. Versuchen Sie, den Code nicht stark zu ändern

Lösung

1 . Einfache Golang-Kapselung, kompilieren Sie die Klassenbibliothek eines Drittanbieters. Generieren Sie eine ausführbare Datei

2. PHP und Golang kommunizieren über Zwei-Wege-Pipes

Vorteile der Verwendung von Zwei-Wege-Pipes Way-Pipe-Kommunikation

1: Erfordert nur wenig Kapselung der ursprünglichen Golang-Klassenbibliothek

2: Beste Leistung (IPC-Kommunikation ist die beste Möglichkeit, zwischen Prozessen zu kommunizieren)

3: Es sind keine Netzwerkanfragen erforderlich, was viel Zeit spart

4: Das Programm muss nur einmal initialisiert werden und bleibt im Speicher

Spezifische Implementierungsschritte

1: Die ursprüngliche Aufrufdemo in der Klassenbibliothek

package main
import (
 "fmt"
 "github.com/yanyiwu/gojieba"
 "strings"
)
 
func main() {
 x := gojieba.NewJieba()
 defer x.Free()
 
 s := "小明硕士毕业于中国科学院计算所,后在日本京都大学深造"
 words := x.CutForSearch(s, true)
 fmt.Println(strings.Join(words, "/"))
}

Speichern Sie die Datei als main.go, und Sie können sie ausführen

2 : Der angepasste Code lautet:

package main
import (
 "bufio"
 "fmt"
 "github.com/yanyiwu/gojieba"
 "io"
 "os"
 "strings"
)
 
func main() {
 
 x := gojieba.NewJieba(
  "/data/tmp/jiebaDict/jieba.dict.utf8", 
  "/data/tmp/jiebaDict/hmm_model.utf8", 
  "/data/tmp/jiebaDict/user.dict.utf8"
 )
 defer x.Free()
 
 inputReader := bufio.NewReader(os.Stdin)
 for {
  s, err := inputReader.ReadString('\n')
  if err != nil && err == io.EOF {
   break
  }
  s = strings.TrimSpace(s)
 
  if s != "" {
   words := x.CutForSearch(s, true)
   fmt.Println(strings.Join(words, " "))
  } else {
   fmt.Println("get empty \n")
  }
 }
}

Es sind nur ein paar einfache Anpassungen erforderlich, um dies zu erreichen: Empfangen Sie eine Zeichenfolge von der Standardeingabe, segmentieren Sie sie und geben Sie sie dann aus

Test :

# go build test
# ./test
# //等待用户输入,输入”这是一个测试“
# 这是 一个 测试 //程序

3: Verwenden Sie die Katze, um mit Golang zu kommunizieren. Machen Sie einen einfachen Test.

//准备一个title.txt,每行是一句文本
# cat title.txt | ./test

Normale Ausgabe, was darauf hinweist, dass die Katze normal mit Golang interagieren kann.

4: PHP kommuniziert mit Golang

Katze oben abgebildet Zur Kommunikation mit Golang wird eine Einweg-Pipe verwendet. Das heißt: Daten können nur von cat an Golang übergeben werden. Die von Golang ausgegebenen Daten werden nicht an cat zurückgegeben, sondern direkt auf dem Bildschirm ausgegeben. Die Anforderung im Artikel lautet jedoch: PHP kommuniziert mit Golang. Das heißt, PHP muss Daten an Golang übergeben und Golang muss auch die Ausführungsergebnisse an PHP zurückgeben. Daher muss eine bidirektionale Pipeline eingeführt werden.

Die Verwendung von Pipes in PHP: popen("/path/test"), ich werde nicht auf Details eingehen, da diese Methode das Problem im Artikel nicht lösen kann.

Bidirektionale Pipe:

$descriptorspec = array( 
 0 => array("pipe", "r"), 
 1 => array("pipe", "w")
);
$handle = proc_open(
 '/webroot/go/src/test/test', 
 $descriptorspec, 
 $pipes
);
fwrite($pipes['0'], "这是一个测试文本\n");
echo fgets($pipes[1]);

Erklärung: Verwenden Sie proc_open, um einen Prozess zu öffnen und das Golang-Programm aufzurufen. Gleichzeitig wird ein bidirektionales Pipes-Array zurückgegeben, das Daten in $pipe['0'] schreibt und Daten aus $pipe['1'] liest.

Nun, vielleicht haben Sie herausgefunden, dass ich die Titeldatei bin und der Fokus hier nicht nur darauf liegt, wie PHP und Golang kommunizieren. Stattdessen führen wir eine Methode ein: Ermöglichen, dass jede Sprache über eine Zwei-Wege-Pipeline kommuniziert. (Alle Sprachen implementieren Pipeline-bezogene Inhalte)

Test:

Berechnen Sie durch Vergleichstests die Zeit, die jeder Prozess benötigt. Die unten erwähnte Datei title.txt enthält 1 Million Textzeilen. Jede Textzeile ist der Produkttitel, der von der B2B-Plattform übernommen wurde.

1: Der Gesamtprozess braucht Zeit

time cat title.txt | ./test > /dev/null

Zeit Verbrauch: 14,819 Sekunden, die verbrauchte Zeit umfasst:

Prozesskatze liest den Text

Leitet die Daten über die Pipeline an Golang weiter

Golang verarbeitet den Daten und gibt das Ergebnis zurück. Gehen Sie zum Bildschirm

2: Die Berechnung der Wortsegmentierungsfunktion dauert einige Zeit. Lösung: Entfernen Sie den Aufruf der Wortsegmentierungsfunktion, das heißt: Kommentieren Sie die Codezeile aus, die die Wortsegmentierung im Golang-Quellcode aufruft

time cat title.txt | ./test > /dev/null

Zeitverbrauch: 1,817 Sekunden, der Zeitverbrauch umfasst:

Die Prozesskatze liest den Text vor

Übergibt die Daten über die Pipe an Golang

Golang verarbeitet die Daten und gibt das Ergebnis an den Bildschirm zurück

Wortsegmentierung Zeitaufwendig = (im ersten Schritt benötigte Zeit) - (vom obigen Befehl benötigte Zeit)

Wortsegmentierungszeit: 14,819 - 1,817 = 13,002 Sekunden

3: Testen Sie den Cat-Prozess und Golang. Die für die Kommunikation zwischen Prozessen benötigte Zeit

time cat title.txt > /dev/null

beträgt: 0,015 Sekunden, die verbrauchte Zeit umfasst:

Process Cat liest den Text

Die Daten werden durch die Pipeline Pass in Golang geleitet

go verarbeitet die Daten und gibt die Ergebnisse an den Bildschirm zurück

Pipeline-Kommunikation zeitaufwändig: (Der zweite Schritt braucht Zeit) - (Der dritte Schritt braucht Zeit)

Pipeline-Kommunikationszeitverbrauch: 1,817 - 0,015 = 1,802 Sekunden

4: Zeitverbrauch von PHP- und Golang-Kommunikation

Schreiben Sie eine einfache PHP-Datei:

<?php
 $descriptorspec = array( 
  0 => array("pipe", "r"), 
  1 => array("pipe", "w")
 );
 
 $handle = proc_open(
  &#39;/webroot/go/src/test/test&#39;, 
  $descriptorspec, 
  $pipes
 );
 
 $fp = fopen("title.txt", "rb");
 
 while (!feof($fp)) {
  fwrite($pipes[&#39;0&#39;], trim(fgets($fp))."\n");
  echo fgets($pipes[1]);
 }
 
 fclose($pipes[&#39;0&#39;]);
 fclose($pipes[&#39;1&#39;]);
 proc_close($handle);

Der Prozess ist im Grunde der gleiche wie oben. Lesen Sie den Inhalt von title.txt und übergeben Sie ihn an den Golang-Prozess Wortsegmentierung über eine Zwei-Wege-Pipe und anschließende Rückgabe an PHP (ein Schritt mehr als der obige Test: Die Daten werden über die Pipe zurückgegeben)

time php popen.php > /dev/null

Zeitverbrauch: 24,037 Sekunden, Zeitverbrauch inklusive :

PHP liest Text verarbeiten

Daten über Pipes an Golang übergeben

Golang verarbeitet die Daten

Golang gibt das Ergebnis zurück Schreiben an die Pipe, PHP empfängt Daten über die Pipe

Ergebnis auf dem Bildschirm zurückgeben

Schlussfolgerung:

1: Im Ganzen Wortsegmentierungsprozess Zeitaufwändige Verteilung

Verwenden Sie die Cat-Steuerungslogik, um zu dauern: 14,819 Sekunden

Verwenden Sie PHP, um die Logik zu steuern: 24,037 Sekunden (eine Pipeline-Kommunikation mehr als Cat)

Einweg-Pipeline-Kommunikation dauert 1,8 Sekunden

Die Wortsegmentierungsfunktion in Golang dauert 13,002 Sekunden

2: Leistung der Wortsegmentierungsfunktion: Einzelvorgang. Die Segmentierung von 1 Million Produkttiteln dauert 13 Sekunden

Die oben genannte Zeit umfasst nur die Wortsegmentierungszeit und nicht die Wörterbuchladezeit. Aber in dieser Lösung wird das Wörterbuch nur einmal geladen, sodass die Ladezeit des Wörterbuchs ignoriert werden kann (ca. 1 Sekunde)

3: PHP ist langsamer als cat (diese Schlussfolgerung ist etwas überflüssig, haha)

Langsam auf Sprachebene: (24.037 - 1.8 - 14.819) / 14.819 = 50 %

In einem Einzelprozess-Vergleichstest sollte es keine Sprache geben, die schneller ist als cat .

Verwandte Fragen:

1: Was im obigen Golang-Quellcode geschrieben steht, ist eine Schleife, das heißt, Daten werden immer aus der Pipe gelesen. Es stellt sich also die Frage: Wird der Golang-Prozess nach dem Ende des PHP-Prozesses noch existieren?

Der Rohrmechanismus selbst löst dieses Problem. Pipes bieten zwei Schnittstellen: Lesen und Schreiben. Wenn der Schreibvorgang unerwartet endet oder aufhängt, meldet der Lesevorgang ebenfalls einen Fehler und die Fehlerlogik im obigen Golang-Quellcode wird ausgeführt und der Golang-Prozess wird beendet.
Wenn der PHP-Prozess jedoch noch nicht beendet ist, aber vorerst keine Daten eingehen, wartet der Golang-Prozess weiter. Der Golang-Prozess wird nicht automatisch beendet, bis PHP beendet ist.

2: Können mehrere PHP-Prozesse dieselbe Pipe parallel lesen und schreiben und der Golang-Prozess bedient sie gleichzeitig?

Nein. Die Pipe ist unidirektional. Wenn mehrere Prozesse gleichzeitig in die Pipe schreiben, wird der Rückgabewert von Golang verwechselt.
Um dies zu erreichen, können Sie mehrere weitere Golang-Prozesse öffnen, und jeder PHP-Prozess entspricht einem Golang-Prozess.

Schließlich ist das oben Genannte alles Unsinn. Wenn Sie sich mit Rohren und bidirektionalen Rohren auskennen, wird Ihnen die obige Erklärung wenig nützen. Wenn Sie sich jedoch nicht mit Pipelines auskennen, ist es in Ordnung, den obigen Code zu debuggen. Sie könnten jedoch in eine Falle tappen, wenn Sie geringfügige Änderungen vornehmen.

Zusammenfassung

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels für alle beim Erlernen oder Verwenden von Golang hilfreich sein kann eine Nachricht zur Kommunikation. Vielen Dank für Ihre Unterstützung für die Unterstützung der chinesischen PHP-Website.

Ausführlichere Erläuterungen zur Kommunikation zwischen PHP und der Go-Sprache finden Sie auf der chinesischen PHP-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