A recently encountered scene: http://www.php.cn/"target=" _blank ">php project needs to use a third-party function (stuttering participle), and GitHub has a class library that is written in Golang. So the question is, how do you achieve communication between different languages?
The general scenario:
Write a http/tcp service with Golang, PHP communicates with Golang via HTTP/TCP
The Golang is more encapsulated as a PHP extension.
PHP uses system commands to fetch Golang executable files.
Problems that exist:
HTTP requests, network I/O will consume a lot of time
Need to encapsulate a lot of code
PHP every time the Golang program, you need to initialize, time consuming a lot
Optimization objectives:
Golang program is initialized only once (because initialization is time-consuming)
All requests do not need to go to the network
Try not to change the code a lot
Solution:
Advantages of using two-way pipeline communication:
1: Only a few packages of the original Golang class library are required
2: Best Performance (IPC communication is the best way to communicate between processes)
3: No need to go network request, save a lot of time
4: The program only needs to be initialized once and remains in memory
Specific implementation steps:
1: Original fetch demo in class library
Package main Import ( "FMT" "Github.com/yanyiwu/gojieba" " Strings" ) func main () { x: = Gojieba. Newjieba () defer x.free () s: = "Xiao Ming Master graduated from the Institute of Chinese Academy of Sciences, after studying at Kyoto University in Japan" Words: = X.cutforsearch (S, true) FMT. PRINTLN (Strings. Join (words, "/")) }
Save the file as Main.go and you can run it
2: The adjusted code is:
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")}}}
Only a few simple lines of adjustment are needed to achieve: receive string from standard input, pass word and output
Test:
# Go build Test #./test #//wait for user input, enter "This is a test" # This is a test//program
3: Simple test with cat and Golang communication
Prepare a title.txt, each line is a sentence of text # cat Title.txt |./test
Normal output, which means that cat has been able to interact properly with Golang.
4:php and Golang Communication
The cat shown above communicates with the Golang using a unidirectional pipe. That is, the data can only be passed from cat to Golang, and the data Golang output is not passed back to cat, but is output directly to the screen. However, the requirement in this paper is: PHP communicates with Golang. That is, PHP will pass data to Golang, and Golang must return the execution results to PHP. Therefore, two-way pipelines need to be introduced.
The use of pipelines in PHP: popen("/path/test")
Specifically, do not expand, because this method does not solve the problem in the article.
Bidirectional piping:
$descriptorspec = Array (0 = = Array ( "pipe", "R"), 1 = = Array ("Pipe", "w") ); $handle = Proc_open ( '/webroot/go/src/test/test ', $descriptorspec, $pipes ); Fwrite ($pipes [' 0 '], "This is a test text \ n"); Echo fgets ($pipes [1]);
Explanation: Use Proc_open to open a process and invoke the Golang program. Also returns a bidirectional pipe pipes array, PHP writes data to $pipe[' 0 '], reading data from $pipe[' 1 '].
Well, maybe you've found out that I'm the title file, and the focus here is not just about how PHP communicates with Golang. Instead, it introduces a way to communicate in any language through a two-way pipeline. (all languages will implement pipeline related content)
Test:
The time taken by each process is calculated by comparing the tests . The Title.txt file mentioned below contains 1 million lines of text, and each line of text is a product title taken from the business-to-business platform
1: Overall process time-consuming
time cat title.txt | ./test > /dev/null
Time-consuming: 14.819 seconds, consumption times include:
Process Cat read out text
Passing data to Golang through a pipeline
Golang processing data, returning the results to the screen
2: Calculate the time-consuming function of word breaker. Scenario: Remove the word-breaker function, that is: Comment out the Golang source code of the word to the line of the code
time cat title.txt | ./test > /dev/null
Time consuming: 1.817 seconds, consumption time includes:
Process Cat read out text
Passing data to Golang through a pipeline
Golang processing Data , returning the results to the screen
participle time consuming = (The first step takes time)-(The above command is time consuming)
participle time: 14.819-1.817 = 13.002 seconds
3: Test the time taken to communicate between the cat process and the Golang process
time cat title.txt > /dev/null
Time-consuming: 0.015 seconds, consumption times include:
Process Cat read out text
Passing data to Golang through a pipeline
Go process data , return the results to the screen
Pipeline communication Time consuming:(second step takes time)-(the third step takes time)
Pipeline Communication time: 1.817-0.015 = 1.802 seconds
Time consumption of 4:php and Golang communication
Write a simple PHP file:
<?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);
The process is basically the same as above, read out the Title.txt content, through the bidirectional pipeline into the Golang process participle, and then return to PHP (more than one step above the test: Data again through the pipeline back)
time php popen.php > /dev/null
Time-consuming: 24.037 seconds, consumption times include:
Process PHP read out text
Passing data to Golang through a pipeline
Golang processing Data
Golang returns the results to the pipeline, and PHP receives the data through the pipeline
Return the results to the screen
Conclusion:
1: Time-consuming distribution throughout the word segmentation process
Using Cat control logic time consuming: 14.819 seconds using PHP control logic time: 24.037 seconds (one more pipe communication than cat) time consuming: 1.8 seconds the word breaker function in Golang time: 13.002 Seconds
2: The performance of the word breaker function: single process, 1 million product title participle, time 13 seconds
The above time only includes the word breaker time, not including the dictionary loading time. However, in this scenario, the dictionary is loaded only once, so loading the dictionary time can be ignored (about 1 seconds)
3:php is slower than cat (this conclusion is a bit superfluous, hehe)
Language level Slow: (24.037-1.8-14.819)/14.819 = 50%
Single-process comparison test, there should be no language faster than cat.
Related issues:
-
1: The above Golang source is written in a loop, which will always read the data from the pipeline. Then there is a question: is the Golang process still there after the end of the PHP process? The
Pipeline mechanism itself resolves this issue. The pipeline provides two interfaces: Read and write. When the write process ends or accidentally hangs, the read process will also error, the above Golang source code in the Err logic will be executed, Golang process end.
But if the PHP process does not end, only temporarily no data is passed in, at which point the Golang process waits. The Golang process will not end automatically until after PHP is finished.
-
2: Can multiple PHP processes read and write to the same pipeline in parallel, and the Golang process serves it at the same time?
Not available. The pipeline is unidirectional, and if multiple processes are written to the pipeline at the same time, the return value of the Golang will be garbled. The
can open several Golang process implementations, each of which corresponds to a golang process.