首頁 php教程 PHP开发 PHP與Go語言的溝通詳解

PHP與Go語言的溝通詳解

Dec 28, 2016 pm 03:50 PM

前言

最近工作中遇到的一個場景,php專案中需要使用一個第三方的功能,而恰好有一個用Golang寫好的類別庫。那麼問題就來了,要如何實現不同語言之間的溝通呢?下面就來一起看看吧。

常規的方案

    1、 用Golang寫一個http/TCP服務,php透過http/TCP與Golang通訊

     2、將Golang經過較多封裝,做為php。

     3、PHP透過系統指令,調取Golang的執行檔

存在的問題

    

     3、PHP每調取一次Golang程序,就需要一次初始化,時間消耗很多


最佳化目標


     1.Golang需要走網


     3.盡量不大量修改程式碼


解決方案


    管線通訊


使用雙向管道通訊優勢


     1:只需要對原有Golang類庫進行很少的封裝


   

     3:不需要走網請求,節省大量時間

     4:程式只需初始化一次,並保持在記憶體中

具體實現步驟


儲存檔案為main.go,就可以運行

2:調整後程式碼為:

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, "/"))
}
登入後複製

只需要簡單的幾行調整,即可實現:從標準輸入接收字串,經過分詞再輸出


測試:

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")
  }
 }
}
登入後複製

3:使用cat與Golang通信做簡單測試

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

正常輸出,表示cat已經可以和Golang正常交互了

4:PHP與Golang通信

  以上所示的cat與Golang通訊

  以上所示的cat與Golang通訊,使用的cat是單向管道。即:只能從cat向Golang傳入數據,Golang輸出的數據並沒有傳回給cat,而是直接輸出到螢幕。但文中的需求是:php與Golang通訊。即php要傳遞資料給Golang,同時Golang也必須把執行結果回傳給php。因此,需要引入雙向管道。

  在PHP中管道的使用:popen("/path/test") ,具體就不展開說了,因為此方法解決不了文中的問題。

雙向管道:

//准备一个title.txt,每行是一句文本
# cat title.txt | ./test
登入後複製

解釋:使用proc_open開啟一個進程,呼叫Golang程式。同時傳回一個雙向管道pipes數組,php寫入$pipe['0']數據,從$pipe['1']讀取資料。


好吧,也許你已經發現,我是標題檔,這裡重點要講的不只是PHP與Golang如何溝通。而是在介紹一種方法: 透過雙向管道讓任意語言溝通。 (所有語言都會實現管道相關內容)

測試:

通過對比測試,計算出各個流程佔用的時間。以下提到的title.txt文件,包含100萬行文本,每行文字是從b2b平台取的商品標題

1: 整體流程耗時

$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]);
登入後複製

耗時:14.819秒,消耗時間包含:

   cat讀出文字

     透過管道將資料傳入Golang

     Golang處理數據,將結果回復至螢幕

2:計算分詞函數耗時。方案:去除分詞函數的調取,即:註解掉Golang原始碼中的調取分詞那行的程式碼

time cat title.txt | ./test > /dev/null
登入後複製
登入後複製

耗時:1.817秒時間,消耗時間包含:


    管道將資料傳入Golang


     Golang處理數據,將結果回傳至螢幕


分詞耗時= (第一步耗時) - (上述指令所耗時)

分詞與第一步耗時) - (上述指令所耗時)

分詞詞= 13.002秒

3:測試cat進程與Golang進程之間通訊所佔時間

time cat title.txt | ./test > /dev/null
登入後複製
登入後複製

耗時:0.015秒,消耗時間包含:

      

     go處理數據,將結果返回螢幕


管道通訊耗時:(第二步耗時) - (第三步耗時)

管道通訊耗時: 1.817秒 - 0.002 4:PHP與Golang通訊的時間消耗

編寫簡單的php檔案:

time cat title.txt > /dev/null
登入後複製

流程與上面基本一致,讀出title.txt內容,透過雙向管道傳入Golang進程分詞後,再傳回給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);
登入後複製

耗時:24.037秒,消耗時間包含:

     進程PHP讀出文字

     將資料傳入Golang

     Golang    將結果回到螢​​幕

結論:

1 :整個分詞過程中的耗時分佈

    使用cat控制邏輯耗時:        14.819 秒 多一次管道通訊)


    單向管道通訊耗時:           1.8    秒

    Golang中的分詞函數耗時:    

    以上時間只包括分詞時間,不包括字典載入時間。但在這個方案中,字典只載入一次,所以載入字典時間可以忽略(1秒左右)

3:PHP比cat慢(這結論有點多餘了,呵呵)


    語言層面慢: (24.037 - 1.8 - 14.819) / 14.819 = 50%


單進程對比測試的話,應該不會有哪個語言比cat更快。


相關問題:

1:以上Golang原始碼中寫的是一個循環,也就是會一直從管道中讀取資料。那麼存在一個問題:是不是php進程結束後,Golang的進程還會一直存在?


管道機製本身可解決此問題。管道提供兩個介面:讀取、寫入。當寫入進程結束或意外掛掉時,讀取進程也會報錯,以上Golang原始碼中的err邏輯就會執行,Golang進程結束。

但如果PHP進程沒有結束,只是暫時沒有資料傳入,此時Golang進程會一直等待。直到php結束後,Golang進程才會自動結束。


2:能否多個php進程並行讀取寫同一個管道,Golang進程同時為其服務?

不可以。管道是單向的,如果多個進程同時向管道中寫,那麼Golang的回傳值就會錯亂。

可以多開幾個Golang進程實現,每個php進程對應一個Golang進程。

最後,上面都是瞎扯的。如果你了解管道、雙向管道,上面的解釋對你基本上沒啥用。但如果你不了解管道,調試上面的程式碼沒問題,但稍有修改就有可能掉坑裡。

總結


以上就是這篇文章的全部內容了,希望本文的內容對大家學習或使用Golang能有所幫助,如果有疑問大家可以留言交流,謝謝大家對PHP中文網的支持。

更多PHP與Go語言之間的通信詳解相關文章請關注PHP中文網!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1323
25
PHP教程
1272
29
C# 教程
1251
24