PHP hybrid Go coprocessor concurrency

Source: Internet
Author: User
Tags call back
This is a creation in Article, where the information may have evolved or changed.

The idea is simple. By setting the runtime.GOMAXPROCS(1) Golang process into single-threaded execution. Similar to Python with gevent effect. asynchronous I/O concurrency is then implemented by scheduling multiple threads. PHP runs in the go process as a sub-function, and PHP needs to yield to other threads, through callbacks to the Golang function. When you invoke the child function provided by go from PHP, go guarantees that the current context of PHP is saved. The original PHP context is restored when the co-process execution is allowed to return. The key code is:

// 保存当前协程上的php上下文    oldServerCtx := engine.ServerContextGet()    fmt.Println(oldServerCtx)    defer engine.ServerContextSet(oldServerCtx)    oldExecutorCtx := engine.ExecutorContextGet()    fmt.Println(oldExecutorCtx)    defer engine.ExecutorContextSet(oldExecutorCtx)    oldCoreCtx := engine.CoreContextGet()    fmt.Println(oldCoreCtx)    defer engine.CoreContextSet(oldCoreCtx)// 放弃全局的锁,使得其他的协程可以开始执行php    engineLock.Unlock()    defer engineLock.Lock()

Servercontextget These functions are I add, get the PHP (EG/SG/PG) These three global context (see: Http://www.cnblogs.com/chance ... )。 Modified github.com/deuill/go-php source code in: Https://github.com/taowen/go-...

Demo of the complete Php/go hybrid process:

Package Mainimport ("FMT" "Github.com/deuill/go-php/engine" "OS" "Runtime" "Time" "Sync") type Testobj s Truct{}func newtestobj (args []interface{}) interface{} {return &testobj{}}var enginelock *sync. Mutexfunc (self *testobj) Hello () {oldserverctx: = engine. Servercontextget () fmt. PRINTLN (OLDSERVERCTX) defer engine. Servercontextset (oldserverctx) Oldexecutorctx: = engine. Executorcontextget () fmt. PRINTLN (OLDEXECUTORCTX) defer engine. Executorcontextset (oldexecutorctx) Oldcorectx: = engine. Corecontextget () fmt. PRINTLN (OLDCORECTX) defer engine. Corecontextset (OLDCORECTX) Enginelock.unlock () defer enginelock.lock () time. Sleep (time. Second) fmt. Println ("Sleep Done")}func main () {runtime. Gomaxprocs (1) theengine, err: = engine. New () Enginelock = &sync. mutex{} if Err! = Nil {fmt. PRINTLN (Err)} _, Err = Theengine.define ("Testobj", Newtestobj) WG: = &sync. waitgroup{} WG. ADD (2) Before: = time. Now () fmt. Println ("1") go func () {Enginelock.lock () defer enginelock.unlock () context1, err: = Theengine.ne Wcontext () if err! = Nil {fmt. PRINTLN (Err)} context1. Output = OS. Stdout If Err! = Nil {fmt. PRINTLN (Err)} FMT. Println ("1 Enter") _, Err = Context1. Eval ("$TESTOBJ = new Testobj ();        $TESTOBJ->hello (); ") Fmt. Println ("1 back") if err! = Nil {fmt. PRINTLN (Err)}//theengine.destroycontext (CONTEXT1) fmt. Println ("1 Done") WG. Done ()} () Fmt. Println ("2") go func () {Enginelock.lock () defer enginelock.unlock () context2, err: = Theengine.ne Wcontext () if err! = Nil {fmt. PRINTLN (ERR)} if err! = Nil {fmt. PRINTLN (Err)} context2. Output = OS. Stdout FMT. Println ("2 Enter") _, Err = Context2. Eval ("$TESTOBJ = new Testobj (); $TESTOBJ->hello ();") Fmt. Println ("2 Back") if err! = Nil {fmt. PRINTLN (Err)}//theengine.destroycontext (CONTEXT2) fmt. Println ("2 Done") WG. Done ()} () WG. Wait () After: = time. Now () Fmt. Println (after. Sub (before))}

Execution result is

122 enter{0x2cf2930 {<nil> <nil> <nil> 0 <nil> <nil> <nil> <nil> 0 0 0 [0 0 0 0 0] <nil> <nil> <nil> <nil> <nil> <nil> <nil> 0 0 <nil> 1000 [0 0 0 0]} {{& lt;nil> <nil> 0 0x7f682e819780 0 [0 0 0 0 0 0 0] <nil>} 0 1 [0 0 0] <nil> <nil>} 0 0 0 [0 0  0 0 0 0] {0 0 0 0 0 0 0 0 0 0 0 {0 0} {0 0} {0 0} [0 0 0]} 0x2a00270 0x2a00f60 <nil> 8388608 0 1 [0 0 0] 0 {8 7 2 [0 0 0 0] 0 0x29f4520 0x29f4520 0x29f4470 0x29f4420 <nil> 1 0 0 [0 0 0 0 0]} <nil> {0 [0 0 0 0 0 0 0] <nil&gt ; <nil> <nil> <nil>} 0 [0 0 0 0 0 0 0]}{0x7ffd30bac588 {[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 2 0 0 [0 0]} 0x7 f682f01b928 {[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 1 0 0 [0 0]} 0x7f682f01b948 [<nil> <nil> <nil> <nil&gt ; <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>] 0x7f682f01ba60 0x7f682f01b960 0x7f682f167168 0x7f682f01ba88 {5 [0 0 0 0] 0 0x7f682f1972d8 0x7f682f1972d8 0x7f682f1993f8 0x7f682f1970c8 0x7f682e862d10 0 0 1 [0 0 0 0 0]} {8 0 0 [0 0 0 0] 0 <nil> <nil> <nil> 0x7f682f016a00 <nil> 0 0 1 [0 0 0 0 0]} 0x7ffd30bac59 0 22527 0 0 [0 0 0 0] 0x7f682f197640 0x29f4f80 0x29f4fd0 0x29f5070 <nil> 0x2cf2950 0x7f682f1989c0 0 1 [0 0 0] &lt ;nil> <nil> 0 1 [0 0 0 0 0 0] {8 0 0 [0 0 0 0] 1 <nil> <nil> <nil> 0x7f682f016a00 0x7f682e88314 0 0 0 1 [0 0 0 0 0]} {8 0 0 [0 0 0 0] 0 <nil> <nil> <nil> 0x7f682f016a00 0x7f682e8831d0 1 0 0 [0 0 0 0 0  ]} 0x7f682f167088 0 [0 0 0 0] <nil> <nil> {0 0 <nil>} {0 0 <nil> <nil> 0 [0 0 0 0 0 0 0]} {0 0 <nil> <nil> 0 [0 0 0 0 0 0 0]}  0 [0 0 0 0] <nil> 0 0 0x29fb2e0 <nil> <nil> {0x7f682f187030 2 1024-1 [0 0 0 0]} <nil> <nil> <nil> [{0x7f682e915050 [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 0 0 149 8 8 8} {0x7f682e915050 [0 0 0  0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 0 0 149 8 8 8} {0x7f682e915050 [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0]  0 0 0 0] 0 0 149 8 8 8}] 0x7f682f167168 <nil> {0 [0 0 0 0] <nil> 0 [0 0 0 0] 0 0 [0 0 0 0] <nil> 0 [0 0 0 0] <nil>} 1 [0 0 0 0 0 0 0] <nil> 0x7f682f01bde8 895 [0 0 0 0 0 0] [<nil> <nil> <nil> &lt  ; nil>]}{1 [0 0 0 0 0 0 0] 0 0 0 [0 0 0 0 0 0] <nil> 0x29ff9a0 17 134217728-1 0 0 0 1 [0 0 0 0] 1024 0 0 1 [0 0 0 0 0] 0x2a00870 <nil> 0x2a010a0 0x7f682ecc58b0 <nil> 0x7f682ecc5c23 <nil> <nil> <nil> 209715 2 <nil> <nil> 0x2a00180 0x2a00230 <nil> <nil> <nil> {0x7f682ec91aa8 0x7f682ec91aa8} 0x2a00910 {0 0 0 [0 0 0 0] 0 <nil> <nil> <nil> <nil> <nil> 0 0 0 [0 0 0 0 0]} 0 0 0 [0 0 0] {0x2b6dc10 0x2 B6DC10 1 8 <nil> 1 [0 0 0 0 0 0 0] <nil>} [0x7f682f197330 0x7f682f197040 0x7f682f197410 <nil> <nil&gt ; 0X7F682F1974F0] 0 1 1 [0 0 0 0 0] 0x7f682ec9544b 0x7f682ec9544b 0 0 [0 0 0 0 0 0] 0 [0 0 0 0 0 0 0 0] 1 1 1 1 1 0 1 [0] 0 [0 0 0 0] <nil> <nil> 0 [0 0 0 0] 0x2cf27c0 <nil> 0 0 [0 0 0 0 0 0] 0 [0 0 0 0 0 0 0] 0x7f682ecc 6270 0x2a009b0 1 [0 0 0 0 0 0 0] <nil> 0 [0 0 0 0 0 0 0]}1 enter{0x7f6818000aa0 {<nil> <nil> <nil > 0 <nil> <nil> <nil> <nil> 0 0 0 [0 0 0 0 0] <nil> <nil> <nil> <nil> & lt;nil> <nil> <nil> 0 0 <nil> [0 0 0 0]} {{<nil> <nil> 0 0x7f682e819780 0 [0 0 0  0 0 0 0] <nil>} 0 1 [0 0 0] <nil> <nil>} 0 0 0 [0 0 0 0 0 0] {0 0 0 0 0 0 0 0 0 0 0 {0 0} {0 0} {0 0} [0 0 0]} 0x2a00270 0x2a00f60 <nil> 8388608 0 1 [0 0 0] 0 {8 7 2 [0 0 0 0] 0 0x29f4520 0x29f4520 0x29f4470 0x29f4420 <nil> 1 0 0 [0 0 0 0 0]} <nil> {0 [0 0 0 0 0 0 0] <nil> <nil> <nil> <nil>} 0 [0 0 0 0 0 0 0]}{0X7F682A4CCCD8 { [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 2 0 0 [0 0]} 0x7f682f01b928 {[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 1 0 0 [0 0]} 0x7f682f01b9 [<nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil& Gt <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil> <nil>] 0x7f682f01ba60 0x7f682f01b960 0x7f682802f110 0x7f682f01ba88 {5 [0 0 0 0] 0 0x7f682f197a00 0 X7f682f197a00 0x7f682f198368 0x7f682f198fa0 0x7f682e862d10 0 0 1 [0 0 0 0 0]} {8 0 0 [0 0 0 0] 0 <nil> <nil> & Lt;nil> 0x7f682f016a00<nil> 0 0 1 [0 0 0 0 0]} 0x7f682a4ccce0 22527 0 0 [0 0 0 0] 0x7f682f197d28 0x29f4f80 0x29f4fd0 0x29f5070 <nil> 0x2cf2950 0x7f682f1983e8 0 1 [0 0 0] <nil> <nil> 0 1 [0 0 0 0 0 0] {8 0 0 [0 0 0 0] 1 <nil> <nil& Gt <nil> 0x7f682f016a00 0x7f682e883140 0 0 1 [0 0 0 0 0]} {8 0 0 [0 0 0 0] 0 <nil> <nil> <nil> 0x7f68 2f016a00 0x7f682e8831d0 1 0 0 [0 0 0 0 0]} 0x7f682802f030 0 [0 0 0 0] <nil> <nil> {0 0 <nil>} {0 0 <n il> <nil> 0 [0 0 0 0 0 0 0]} {0 0 <nil> <nil> 0 [0 0 0 0 0 0 0]} 0 [0 0 0 0] <nil> 0 0 0x29fb2e  0 <nil> <nil> {0x7f682804efd8 2 1024-1 [0 0 0 0]} <nil> <nil> <nil> [{0x7f682e915050] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 0 0 149 8 8 8} {0x7f682e915050 [0 0] 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 0 0 149 8 8 8} {0x7f682e915050 [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 0 0 149 8 8 8}] 0x7f682802 F110 <nil> {0[0 0 0 0] <nil> 0 [0 0 0 0] 0 0 [0 0 0 0] <nil> 0 [0 0 0 0] <nil>} 1 [0 0 0 0 0 0 0] <nil> 0x7f682 F01bde8 895 [0 0 0 0 0 0] [<nil> <nil> <nil> <nil>]}{1 [0 0 0 0 0 0 0] 0 0 0 [0 0 0 0 0 0] <nil > 0x29ff9a0 134217728-1 0 0 0 1 [0 0 0 0] 1024x768 0 0 1 [0 0 0 0 0] 0x2a00870 <nil> 0x2a010a0 0x7f682ecc58b0 &lt ;nil> 0x7f682ecc5c23 <nil> <nil> <nil> 2097152 <nil> <nil> 0x2a00180 0x2a00230 <nil& Gt <nil> <nil> {0x7f682ec91aa8 0x7f682ec91aa8} 0x2a00910 {0 0 0 [0 0 0 0] 0 <nil> <nil> <nil> & Lt;nil> <nil> 0 0 0 [0 0 0 0 0]} 0 0 0 [0 0 0] {0x2b6dc10 0X2B6DC10 1 8 <nil> 1 [0 0 0 0 0 0 0] <nil> } [0x7f682f197a58 0x7f682f198ce0 0x7f682f197b38 <nil> <nil> 0x7f682f197c18] 0 1 1 [0 0 0 0 0] 0x7f682ec9544b 0 x7f682ec9544b 0 0 [0 0 0 0 0 0] 0 [0 0 0 0 0 0 0 0] 1 1 1 1 1 0 1 [0] 0 [0 0 0 0] <nil> <nil> 0 [0 0 0 0] 0x2c F27C0 <nil> 0 0[0 0 0 0 0 0] 0 [0 0 0 0 0 0 0] 0x7f682ecc6270 0x2a009b0 1 [0 0 0 0 0 0 0] <nil> 0 [0 0 0 0 0 0 0]}sleep Done1 back1 donesleep done2 back2 done1.00099211s

You can see two sleep 1s, and finally use only 1.00099211s. Indicates that the co-process is concurrent.

Some performance metrics. Go to the HTTP call back end, on i7-6700k, with Ab-n 100-c 4 can run out of such results

Requests per second:    3183.70 [#/sec] (mean)Time per request:       1.256 [ms] (mean)Time per request:       0.314 [ms] (mean, across all concurrent requests)

If you do not use the HTTP call back end, direct php=>go return "Hello", you can achieve

Requests per second:    10073.54 [#/sec] (mean)Time per request:       0.397 [ms] (mean)Time per request:       0.099 [ms] (mean, across all concurrent requests)

These metrics only illustrate the cost of the co-process switchover. The actual gain depends on the latency of the backend HTTP service, and if it takes a long time, the benefits can be significant through concurrent concurrency.

This experiment shows that an application server can be implemented with Golang instead of NGINX+PHP-FPM. It also provides a smooth migration path from PHP to Golang. Mix PHP and go in one app in two languages.

I/O can also be asynchronous by providing the Golang function to the PHP call. Extensions like Libcurl support asynchronous callbacks, except that PHP is synchronous, so only the synchronous execute is exposed to PHP. With Golang, execute can be transformed into an asynchronous execute+callback wrapper, enabling scheduling based on the co-scheduling.

Resources:

    • Https://wiki.php.net/internal ...

    • Http://www.cunmou.com/phpbook

    • Http://www.phpinternalsbook.c

    • http://www.php-internals.com/

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.