自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

開發(fā) 后端
通過設(shè)置 runtime.GOMAXPROCS(1) 讓 golang 的進(jìn)程變成單線程執(zhí)行的。類似python用gevent的效果。然后通過調(diào)度多個(gè)協(xié)程實(shí)現(xiàn)異步I/O并發(fā)。php作為一個(gè)子函數(shù)跑在go的進(jìn)程內(nèi),php需要yield到其他協(xié)程時(shí),通過回調(diào)到golang函數(shù)來實(shí)現(xiàn)。從php里調(diào)用go提供的子函數(shù)時(shí),go保證保存php的當(dāng)前上下文。

[[174762]]

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

  1.  // 保存當(dāng)前協(xié)程上的php上下文    
  2. oldServerCtx := engine.ServerContextGet() 
  3.     fmt.Println(oldServerCtx) 
  4.     defer engine.ServerContextSet(oldServerCtx) 
  5.     oldExecutorCtx := engine.ExecutorContextGet() 
  6.     fmt.Println(oldExecutorCtx) 
  7.     defer engine.ExecutorContextSet(oldExecutorCtx) 
  8.     oldCoreCtx := engine.CoreContextGet() 
  9.     fmt.Println(oldCoreCtx) 
  10.     defer engine.CoreContextSet(oldCoreCtx) 
  11.  
  12. // 放棄全局的鎖,使得其他的協(xié)程可以開始執(zhí)行php 
  13.     engineLock.Unlock() 
  14.     defer engineLock.Lock()  

ServerContextGet 這幾個(gè)函數(shù)是我加的,獲得的是php的(EG/SG/PG)這三個(gè)全局context(參見:http://www.cnblogs.com/chance...)。修改過的github.com/deuill/go-php的源代碼在:https://github.com/taowen/go-...

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

  1. package main 
  2.  
  3. import ( 
  4.     "fmt" 
  5.     "github.com/deuill/go-php/engine" 
  6.     "os" 
  7.     "runtime" 
  8.     "time" 
  9.     "sync" 
  10.  
  11. type TestObj struct{} 
  12.  
  13. func newTestObj(args []interface{}) interface{} { 
  14.     return &TestObj{} 
  15. var engineLock *sync.Mutex 
  16.  
  17. func (self *TestObj) Hello() { 
  18.     oldServerCtx := engine.ServerContextGet() 
  19.     fmt.Println(oldServerCtx) 
  20.     defer engine.ServerContextSet(oldServerCtx) 
  21.     oldExecutorCtx := engine.ExecutorContextGet() 
  22.     fmt.Println(oldExecutorCtx) 
  23.     defer engine.ExecutorContextSet(oldExecutorCtx) 
  24.     oldCoreCtx := engine.CoreContextGet() 
  25.     fmt.Println(oldCoreCtx) 
  26.     defer engine.CoreContextSet(oldCoreCtx) 
  27.     engineLock.Unlock() 
  28.     defer engineLock.Lock() 
  29.     time.Sleep(time.Second
  30.     fmt.Println("sleep done"
  31.  
  32. func main() { 
  33.     runtime.GOMAXPROCS(1) 
  34.     theEngine, err := engine.New() 
  35.     engineLock = &sync.Mutex{} 
  36.     if err != nil { 
  37.         fmt.Println(err) 
  38.     } 
  39.     _, err = theEngine.Define("TestObj", newTestObj) 
  40.     wg := &sync.WaitGroup{} 
  41.     wg.Add(2) 
  42.     before := time.Now() 
  43.     fmt.Println("1"
  44.     go func() { 
  45.         engineLock.Lock() 
  46.         defer engineLock.Unlock() 
  47.         context1, err := theEngine.NewContext() 
  48.         if err != nil { 
  49.             fmt.Println(err) 
  50.         } 
  51.         context1.Output = os.Stdout 
  52.         if err != nil { 
  53.             fmt.Println(err) 
  54.         } 
  55.         fmt.Println("1 enter"
  56.         _, err = context1.Eval("$testObj = new TestObj(); $testObj->Hello();"
  57.         fmt.Println("1 back"
  58.         if err != nil { 
  59.             fmt.Println(err) 
  60.         } 
  61.         //theEngine.DestroyContext(context1) 
  62.         fmt.Println("1 done"
  63.         wg.Done() 
  64.     }() 
  65.     fmt.Println("2"
  66.     go func() { 
  67.         engineLock.Lock() 
  68.         defer engineLock.Unlock() 
  69.         context2, err := theEngine.NewContext() 
  70.         if err != nil { 
  71.             fmt.Println(err) 
  72.         } 
  73.         if err != nil { 
  74.             fmt.Println(err) 
  75.         } 
  76.         context2.Output = os.Stdout 
  77.         fmt.Println("2 enter"
  78.         _, err = context2.Eval("$testObj = new TestObj(); $testObj->Hello();"
  79.         fmt.Println("2 back"
  80.         if err != nil { 
  81.             fmt.Println(err) 
  82.         } 
  83.         //theEngine.DestroyContext(context2) 
  84.         fmt.Println("2 done"
  85.         wg.Done() 
  86.     }() 
  87.     wg.Wait() 
  88.     after := time.Now() 
  89.     fmt.Println(after.Sub(before)) 
  90.  

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

  1. 2 enter 
  2. {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]} 
  3. {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>]} 
  4. {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]} 
  5. 1 enter 
  6. {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]} 
  7. {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>]} 
  8. {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]} 
  9. sleep done 
  10. 1 back 
  11. 1 done 
  12. sleep done 
  13. 2 back 
  14. 2 done 
  15. 1.00099211s 

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

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

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

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

  1. Requests per second: 10073.54 [#/sec] (mean) 
  2.  
  3. Time per request: 0.397 [ms] (mean) 
  4.  
  5. Time per request: 0.099 [ms] (mean, across all concurrent requests)  

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

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

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

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2018-12-04 14:00:41

協(xié)程編程模式PHP

2024-06-27 07:56:49

2021-09-27 23:28:29

Go多協(xié)程并發(fā)

2017-05-02 11:38:00

PHP協(xié)程實(shí)現(xiàn)過程

2024-12-03 15:15:22

2023-11-24 11:15:21

協(xié)程編程

2023-07-27 13:46:10

go開源項(xiàng)目

2017-08-10 15:50:44

PHP協(xié)程阻塞

2021-04-25 09:36:20

Go協(xié)程線程

2023-10-12 09:46:00

并發(fā)模型線程

2023-07-13 08:06:05

應(yīng)用協(xié)程阻塞

2024-05-29 08:05:15

Go協(xié)程通信

2025-02-28 09:04:08

2021-09-16 09:59:13

PythonJavaScript代碼

2022-10-28 10:45:22

Go協(xié)程GoFrame

2021-05-13 21:58:00

高并發(fā)應(yīng)用Asyncio

2024-08-27 09:46:39

Go協(xié)程效率

2021-05-21 08:21:57

Go語言基礎(chǔ)技術(shù)

2025-01-26 00:00:15

PHP協(xié)程控制權(quán)

2021-06-03 14:08:03

開發(fā)技能代碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號