前言
最近工作中遇到的一個場景,php專案中需要使用一個第三方的功能,而恰好有一個用Golang寫好的類別庫。那麼問題就來了,要如何實現不同語言之間的溝通呢?下面就來一起看看吧。
常規的方案
1、 用Golang寫一個http/TCP服務,php透過http/TCP與Golang通訊
2、將Golang經過較多封裝,做為php。
3、PHP透過系統指令,調取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 # //等待用户输入,输入”这是一个测试“ # 这是 一个 测试 //程序
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平台取的商品標題
$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秒
time cat title.txt | ./test > /dev/null
管道通訊耗時: 1.817秒 - 0.002 4:PHP與Golang通訊的時間消耗
編寫簡單的php檔案:time cat title.txt > /dev/null
<?php $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w") ); $handle = proc_open( '/webroot/go/src/test/test', $descriptorspec, $pipes ); $fp = fopen("title.txt", "rb"); while (!feof($fp)) { fwrite($pipes['0'], trim(fgets($fp))."\n"); echo fgets($pipes[1]); } fclose($pipes['0']); fclose($pipes['1']); proc_close($handle);
耗時:24.037秒,消耗時間包含:
進程PHP讀出文字
將資料傳入Golang
Golang 將結果回到螢幕
結論:
1 :整個分詞過程中的耗時分佈
Golang中的分詞函數耗時:
以上時間只包括分詞時間,不包括字典載入時間。但在這個方案中,字典只載入一次,所以載入字典時間可以忽略(1秒左右)
相關問題:
管道機製本身可解決此問題。管道提供兩個介面:讀取、寫入。當寫入進程結束或意外掛掉時,讀取進程也會報錯,以上Golang原始碼中的err邏輯就會執行,Golang進程結束。
可以多開幾個Golang進程實現,每個php進程對應一個Golang進程。
以上就是這篇文章的全部內容了,希望本文的內容對大家學習或使用Golang能有所幫助,如果有疑問大家可以留言交流,謝謝大家對PHP中文網的支持。