| 副标题[/!--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)) }  
 (编辑:源码网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |