副标题[/!--empirenews.page--]
想法很简单。通过设置 runtime.GOMAXPROCS(1) 让 golang 的进程变成单线程执行的。类似python用gevent的效果。然后通过调度多个协程实现异步I/O并发。php作为一个子函数跑在go的进程内,php需要yield到其他协程时,通过回调到golang函数来实现。从php里调用go提供的子函数时,go保证保存php的当前上下文。当协程执行权让渡回来的时候,把原来的php上下文恢复。关键的代码在:
- // 保存当前协程上的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 这几个函数是我加的,获得的是php的(EG/SG/PG)这三个全局context(参见:http://www.cnblogs.com/chance...)。修改过的github.com/deuill/go-php的源代码在:https://github.com/taowen/go-...
完整的php/go混合协程的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))
- }
(编辑:武汉站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|