想法很简单。通过设置 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... )。修改过的php-go的源代码在: 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()</