Maison >php教程 >PHP开发 >Explication détaillée de la communication entre PHP et le langage Go

Explication détaillée de la communication entre PHP et le langage Go

高洛峰
高洛峰original
2016-12-28 15:50:412446parcourir

Avant-propos

Un scénario que j'ai rencontré récemment au travail était qu'une fonction tierce devait être utilisée dans le projet PHP, et il se trouvait qu'il y avait une bibliothèque de classes écrite en Golang. La question devient alors : comment parvenir à la communication entre différentes langues ? Jetons un coup d'œil ci-dessous.

Solution conventionnelle

1. Utilisez Golang pour écrire un service http/TCP, et php communique avec Golang via http/TCP

2. Mettez Golang via plus Encapsulé sous forme d'extension php.

3. PHP appelle le fichier exécutable Golang via les commandes système

Problèmes

1. Requête http, les E/S réseau consommeront beaucoup de temps

2. Une grande quantité de code doit être encapsulée

3. Chaque fois que PHP appelle un programme Golang, il a besoin d'une initialisation, ce qui consomme beaucoup de temps

Objectifs d'optimisation

1. Le programme Golang n'est initialisé qu'une seule fois (car l'initialisation prend du temps)

2. Toutes les demandes n'ont pas besoin de passer par le Réseau

3. Essayez de ne pas trop modifier le code

Solution

1 . Encapsulation Golang simple, compilez la bibliothèque de classes tierce Générez un fichier exécutable

2. PHP et Golang communiquent via des canaux bidirectionnels

Avantages de l'utilisation de deux-. way pipe communication

1 : Ne nécessite que très peu d'encapsulation de la bibliothèque de classes Golang d'origine

2 : Meilleures performances (la communication IPC est le meilleur moyen de communiquer entre les processus)

3 : Aucune requête réseau n'est requise, ce qui permet de gagner beaucoup de temps

4 : Le programme ne doit être initialisé qu'une seule fois et reste en mémoire

Étapes spécifiques de mise en œuvre

1 : La démo d'appel originale dans la bibliothèque de classes

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, "/"))
}

enregistrez le fichier sous main.go et vous pouvez exécuter

2 : Le code ajusté est :

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")
  }
 }
}

Il suffit de quelques ajustements simples pour y parvenir : recevoir une chaîne de l'entrée standard, la segmenter puis la sortir

Test :

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

3 : Utiliser le chat pour communiquer avec Golang Faire un test simple

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

Sortie normale, indiquant que le chat peut interagir avec Golang normalement

4 : PHP communique avec Golang

Chat illustré ci-dessus Pour communiquer avec Golang, un tube unidirectionnel est utilisé. Autrement dit : les données ne peuvent être transmises que de cat à Golang. Les données sorties par Golang ne sont pas renvoyées à cat, mais sont directement affichées à l'écran. Mais l'exigence de l'article est la suivante : php communique avec Golang. Autrement dit, php doit transmettre les données à Golang, et Golang doit également renvoyer les résultats d'exécution à php. Un pipeline bidirectionnel doit donc être mis en place.

L'utilisation des pipes en PHP : popen("/path/test"), je n'entrerai pas dans les détails car cette méthode ne peut pas résoudre le problème de l'article.

Pipe bidirectionnelle :

$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]);

Explication : Utilisez proc_open pour ouvrir un processus et appeler le programme Golang. En même temps, un tableau de tuyaux bidirectionnel est renvoyé. PHP écrit les données dans $pipe['0'] et lit les données dans $pipe['1'].

Eh bien, peut-être avez-vous découvert que je suis le fichier titre, et que l'accent ici n'est pas seulement sur la façon dont PHP et Golang communiquent. Au lieu de cela, nous introduisons une méthode : permettre à n’importe quelle langue de communiquer via un canal bidirectionnel. (Toutes les langues implémenteront le contenu lié au pipeline)

Test :

Grâce à des tests de comparaison, calculez le temps pris par chaque processus. Le fichier title.txt mentionné ci-dessous contient 1 million de lignes de texte. Chaque ligne de texte est le titre du produit extrait de la plateforme b2b

1 : Le processus global prend du temps

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

Du temps. consommation : 14,819 secondes, le temps consommé comprend :

Process cat lit le texte

Transmet les données à Golang via le pipeline

Golang traite le data et renvoie le résultat Allez à l'écran

2 : Il faut du temps pour calculer la fonction de segmentation des mots. Plan : Supprimer l'appel de la fonction de segmentation de mots, c'est-à-dire : commenter la ligne de code qui appelle la segmentation de mots dans le code source de Golang

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

Prend du temps : 1,817 secondes, le temps consommé comprend :

Le processus cat lit le texte

Transmet les données à Golang via le tuyau

Golang traite les données et renvoie le résultat à l'écran

Segmentation des mots prend du temps = (temps pris dans la première étape) - (temps pris par la commande ci-dessus)

Temps de segmentation des mots : 14,819 - 1,817 = 13,002 secondes

3 : Test cat process et Golang Le temps nécessaire à la communication entre les processus

time cat title.txt > /dev/null

prend : 0,015 seconde, le temps consommé comprend :

Le processus cat lit le texte

Les données passent par le pipeline Pass in Golang

go traite les données et renvoie les résultats à l'écran

Pipeline la communication prend du temps : (La deuxième étape prend du temps) - (La troisième étape prend du temps)

Consommation de temps de communication du pipeline : 1,817 - 0,015 = 1,802 secondes

4 : Consommation de temps de communication PHP et Golang

Écrivez un simple fichier php :

<?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);

Le processus est fondamentalement le même que ci-dessus, lisez le contenu title.txt, transmettez-le dans le Golang traiter via le pipeline bidirectionnel après la segmentation des mots, puis le renvoyer à php (une étape de plus que le test ci-dessus : les données sont renvoyées via le pipeline)

time php popen.php > /dev/null

Consommation de temps : 24,037 secondes, la consommation de temps comprend :

Processus PHP lit le texte

Transmettre les données dans Golang via des tuyaux

Golang traite les données

Golang renverra le résultat Écrire à le tuyau, PHP reçoit les données via le tuyau

Renvoie le résultat à l'écran

Conclusion :

1 : Dans le mot entier processus de segmentation Distribution fastidieuse

Utilisez la logique de contrôle cat pour prendre : 14,819 secondes

Utilisez PHP pour contrôler la logique : 24,037 secondes (une communication pipeline de plus que cat)

La communication pipeline unidirectionnelle prend 1,8 secondes

La fonction de segmentation de mots dans Golang prend 13,002 secondes

2 : Performance de la fonction de segmentation de mots : simple processus, il faut 13 secondes pour segmenter 1 million de titres de produits

Le temps ci-dessus inclut uniquement le temps de segmentation des mots et n'inclut pas le temps de chargement du dictionnaire. Mais dans cette solution, le dictionnaire n'est chargé qu'une seule fois, donc le temps de chargement du dictionnaire peut être ignoré (environ 1 seconde)

3 : PHP est plus lent que cat (cette conclusion est un peu redondante, haha)

Lent au niveau du langage : (24.037 - 1.8 - 14.819) / 14.819 = 50%

Dans un test de comparaison à processus unique, il ne devrait y avoir aucun langage plus rapide que le chat .

Questions connexes :

1 : Ce qui est écrit dans le code source Golang ci-dessus est une boucle, c'est-à-dire que les données seront toujours lues à partir du tube. Il y a donc une question : le processus Golang existera-t-il toujours après la fin du processus php ?

Le mécanisme de tuyau lui-même résout ce problème. Les tuyaux fournissent deux interfaces : lecture et écriture. Lorsque le processus d'écriture se termine ou raccroche de manière inattendue, le processus de lecture signalera également une erreur, et la logique d'erreur dans le code source Golang ci-dessus sera exécutée et le processus Golang se terminera.
Mais si le processus PHP n'est pas terminé, mais qu'aucune donnée n'arrive temporairement, le processus Golang attendra éternellement. Le processus Golang ne se terminera pas automatiquement tant que php ne sera pas terminé.

2 : Plusieurs processus php peuvent-ils lire et écrire le même tube en parallèle, et le processus Golang les sert en même temps ?

Non. Le tube est à sens unique. Si plusieurs processus écrivent dans le tube en même temps, la valeur de retour de Golang sera confuse.
Vous pouvez ouvrir plusieurs processus Golang supplémentaires pour y parvenir, et chaque processus php correspond à un processus Golang.

Enfin, tout ce qui précède n’a aucun sens. Si vous comprenez les tuyaux et les tuyaux bidirectionnels, l’explication ci-dessus vous est fondamentalement inutile. Mais si vous ne comprenez pas les pipelines, il n'y a aucun problème à déboguer le code ci-dessus, mais si vous le modifiez légèrement, vous risquez de tomber dans un gouffre.

Résumé

Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article pourra être utile à tout le monde dans l'apprentissage ou l'utilisation de Golang. un message à communiquer. Merci pour votre soutien au support du site PHP chinois.

Pour des explications plus détaillées sur la communication entre PHP et le langage Go, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn