PHP 混合 Go 协程并发

jinpengxx8 · · 4769 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

想法很简单。通过设置 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()
    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))

有疑问加站长微信联系

本文来自:CSDN博客

感谢作者:jinpengxx8

查看原文:PHP 混合 Go 协程并发

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:1006366459

4769 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传