分享
  1. 首页
  2. 文章

PHP 混合 Go 协程并发

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

想法很简单。通过设置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群:692541889

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

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏