溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PHP混合Go協(xié)程并發(fā)分析

發(fā)布時(shí)間:2021-11-25 15:13:59 來(lái)源:億速云 閱讀:94 作者:iii 欄目:編程語(yǔ)言

這篇文章主要介紹“PHP混合Go協(xié)程并發(fā)分析”,在日常操作中,相信很多人在PHP混合Go協(xié)程并發(fā)分析問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”PHP混合Go協(xié)程并發(fā)分析”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

想法很簡(jiǎn)單。通過(guò)設(shè)置 runtime.GOMAXPROCS(1) 讓 golang  的進(jìn)程變成單線程執(zhí)行的。類似python用gevent的效果。然后通過(guò)調(diào)度多個(gè)協(xié)程實(shí)現(xiàn)異步I/O并發(fā)。php作為一個(gè)子函數(shù)跑在go的進(jìn)程內(nèi),php需要yield到其他協(xié)程時(shí),通過(guò)回調(diào)到golang函數(shù)來(lái)實(shí)現(xiàn)。從php里調(diào)用go提供的子函數(shù)時(shí),go保證保存php的當(dāng)前上下文。當(dāng)協(xié)程執(zhí)行權(quán)讓渡回來(lái)的時(shí)候,把原來(lái)的php上下文恢復(fù)。關(guān)鍵的代碼在:

 // 保存當(dāng)前協(xié)程上的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)  // 放棄全局的鎖,使得其他的協(xié)程可以開(kāi)始執(zhí)行php     engineLock.Unlock()     defer engineLock.Lock()

ServerContextGet  這幾個(gè)函數(shù)是我加的,獲得的是php的(EG/SG/PG)這三個(gè)全局context

完整的php/go混合協(xié)程的demo:

package main  import (     "fmt"     "github.com/deuill/go-php/engine"     "os"     "runtime"     "time"     "sync" )  type TestObj struct{}  func newTestObj(args []interface{}) interface{} {     return &TestObj{} } var engineLock *sync.Mutex  func (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.NewContext()         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.NewContext()         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)) }

執(zhí)行結(jié)果是

1 2 2 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]} {{<nil> <nil> 0 16 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]} {0x7ffd30bac588 {[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]} 0x7f682f01b948 [<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> <nil> <nil> <nil> <nil>] 0x7f682f01ba60 0x7f682f01b960 0x7f682f167168 0x7f682f01ba88 {64 63 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]} 0x7ffd30bac590 22527 0 0 [0 0 0 0] 0x7f682f197640 0x29f4f80 0x29f4fd0 0x29f5070 <nil> 0x2cf2950 0x7f682f1989c0 14 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> <nil> 0x7f682f016a00 0x7f682e883140 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> <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> 2097152 <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 0x2b6dc10 1 8 <nil> 1 [0 0 0 0 0 0 0] <nil>} [0x7f682f197330 0x7f682f197040 0x7f682f197410 <nil> <nil> 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] 64 1000 0 [0 0 0 0 0 0 0] 0x7f682ecc6270 300 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> <nil> <nil> <nil> 0 0 <nil> 1000 [0 0 0 0]} {{<nil> <nil> 0 16 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]} 0x7f682f01b948 [<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> <nil> <nil> <nil> <nil>] 0x7f682f01ba60 0x7f682f01b960 0x7f682802f110 0x7f682f01ba88 {64 63 5 [0 0 0 0] 0 0x7f682f197a00 0x7f682f197a00 0x7f682f198368 0x7f682f198fa0 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]} 0x7f682a4ccce0 22527 0 0 [0 0 0 0] 0x7f682f197d28 0x29f4f80 0x29f4fd0 0x29f5070 <nil> 0x2cf2950 0x7f682f1983e8 14 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> <nil> 0x7f682f016a00 0x7f682e883140 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]} 0x7f682802f030 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> {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 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}] 0x7f682802f110 <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> <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> 2097152 <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 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 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] 64 1000 0 [0 0 0 0 0 0 0] 0x7f682ecc6270 300 0x2a009b0 1 [0 0 0 0 0 0 0] <nil> 0 [0 0 0 0 0 0 0]} sleep done 1 back 1 done sleep done 2 back 2 done 1.00099211s

可以看到兩個(gè)sleep 1s,最終只用了1.00099211s。說(shuō)明協(xié)程是并發(fā)的。

一些性能指標(biāo)。走h(yuǎn)ttp調(diào)用后端,在i7-6700k上,用ab -n 100 -c 4 可以跑出這樣的結(jié)果

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)

如果不用http調(diào)用后端,直接php=>go返回"hello",則可以達(dá)到

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)

這些指標(biāo)只說(shuō)明了協(xié)程切換的成本。實(shí)際的收益取決于后端的http服務(wù)的延遲,如果耗時(shí)很長(zhǎng),通過(guò)協(xié)程并發(fā)則可以收益明顯。

這個(gè)實(shí)驗(yàn)說(shuō)明了可以用golang實(shí)現(xiàn)一個(gè)代替nginx+php-fpm的應(yīng)用服務(wù)器。并且提供了一條從php向golang遷移的平滑遷移路徑。在一個(gè)應(yīng)用里混合PHP和Go兩種語(yǔ)言。

并且可以通過(guò)提供golang函數(shù)給php調(diào)用的方式實(shí)現(xiàn)I/O的異步化。像libcurl這樣的擴(kuò)展自身是支持異步回調(diào)的,只是php是同步的所以只給php暴露了同步的execute。有了Golang之后,可以把execute變成對(duì)異步execute+callback的包裝,從而實(shí)現(xiàn)基于協(xié)程的調(diào)度。

到此,關(guān)于“PHP混合Go協(xié)程并發(fā)分析”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI