yulihua49 发表于 2016-08-18 12:09

本帖最后由 yulihua49 于 2016-08-18 12:29 编辑

cokeboL 发表于 2016-08-18 11:38 static/image/common/back.gif
go c2sCor()
go s2cCor()
这两句就是启动两个协程,然后

启动两个协程,而不是线程?那么没有并行功能,无法充分利用多核。
我希望看到多线程协程,能够并行,也能把任务在多个线程间切换。要看看你是怎么管理协程与线程的关系。

少线程服务器--- 其实还是多线程服务器,就是线程数不多,大约=核数。要充分利用所有的线程,一旦发生等待就yield,放弃这个任务赶紧接别的任务。

我那个例子只是应用侧代码,很简单,而且是同步异步自适应的。就是:同步框架可以调用它,异步框架也可以调用它,只是需要事先提供yield函数即可。

多线程与多协程的关系在于yield函数内的代码,作为C,当然是非常的庞杂,但是完全可以实现上述需求。

你是每个连接产生3个协程?如果10000个连接来了,就是30000个协程?30000个棧?每个棧就算1M,所需内存?
在C里也是这个问题,我用棧池来解决,就是栈数=线程数,激活的协程才拥有棧。

cokeboL 发表于 2016-08-18 12:21

yulihua49 发表于 2016-08-18 12:09 static/image/common/back.gif
启动两个协程,而不是线程?那么没有并行功能,无法充分利用多核。
我希望看到多线程协程,能够并行,也 ...

golang的协程,是应用层调度,1.4还是哪个版本之前,golang启动默认只用单核,
可以手动设置使用的核心数量,现在比较高版本的golang,启动默认使用硬件核数的
线程数做底层,当然依旧可以手动设置核心数

golang和erlang的协程/进程(erlang把协程叫做进程)调度算法性能都不错,协程
本身也很轻量级,非常棒

cokeboL 发表于 2016-08-18 12:23

所以golang的协程,是多核的,并发的

而且轻量,golang开上万个协程跟玩似的

cokeboL 发表于 2016-08-18 12:30

Golang调度器源码分析
http://www.tuicool.com/articles/JBnMVn3

yulihua49 发表于 2016-08-18 15:06

本帖最后由 yulihua49 于 2016-08-18 15:16 编辑

cokeboL 发表于 2016-08-18 12:21 static/image/common/back.gif
golang的协程,是应用层调度,1.4还是哪个版本之前,golang启动默认只用单核,
可以手动设置使用的核心 ...
主要是不了解。不知道里边的资源,事件如何管理的。如,几万协程,棧空间怎么管?不象erlang,根本就没有局部变量,也不需要多少棧(好像它根本就是共用棧的,进程没有私有棧)。

cokeboL 发表于 2016-08-18 15:52

回复 24# yulihua49


golang协程的栈,好像是不够用的时候语言底层自动扩展,也不需要自己操心

事件,怎么说呢,比如lua里我有这样写:local eventCenter = {}
eventCenter.events = {}


function eventCenter:new(name, event, cb)
        if self.events then
                assert(false, "eventCenter", "eventCenter:new Error: eventCenter addListener, listener already exists!")
                return
        end
        print("eventCenter:new: ", name, event, cb)
        self.events = {event=event, cb=cb}
end


function eventCenter:delete(name)
        self.events = nil
end

function eventCenter:dispatch(event, ...)
        print("eventCenter dispatch: ", event, ...)
        for _, v in pairs(self.events) do
                if event == v.event then
                        print("eventCenter dispatch222: ", event, ...)
                        v.cb(event, ...)
                end
        end
end

return eventCenter因为lua单线程的,不需要锁,其他语言比如golang,new、delete、dispatch的时候上锁就好了
也就算个观察者模式或者发布-订阅吧

跨进程,就用socket,几个new、delete、dispatch,几个消息号和key data就是了

golang进程内的我也写了个,不过是刚接触golang的时候写的,写完没整理代码
import (
        //"fmt"
        "sync"
)

type EventMgr struct {
        listenerMap mapinterface{}
        listeners   mapmapEventHandler
        mutex       *sync.Mutex
        valid       bool
}

var (
        defaultInstance *EventMgr = nil
        instanceMap   map*EventMgr
        instanceMutex   = &sync.Mutex{}
)

func eventHandler(handler EventHandler, event interface{}, args []interface{}) {
        defer PanicHandle(true)
        handler(event, args)
}

func (eventMgr *EventMgr) NewListener(tag interface{}, event interface{}, handler EventHandler) bool {
        eventMgr.mutex.Lock()
        defer eventMgr.mutex.Unlock()

        if _, ok := eventMgr.listenerMap; ok {
                LogError(LOG_IDX, LOG_IDX, "NewListener Error: listener %v exist!", tag)
                return false
        }

        eventMgr.listenerMap = event
        if eventMgr.listeners == nil {
                eventMgr.listeners = make(mapEventHandler)
        }
        eventMgr.listeners = handler

        return true
}

func (eventMgr *EventMgr) DeleteListener(tag interface{}) {
        eventMgr.mutex.Lock()
        defer eventMgr.mutex.Unlock()

        if event, ok := eventMgr.listenerMap; ok {
                delete(eventMgr.listenerMap, tag)
                delete(eventMgr.listeners, tag)
        }
}

func (eventMgr *EventMgr) Dispatch(event interface{}, args ...interface{}) {
        eventMgr.mutex.Lock()
        defer eventMgr.mutex.Unlock()

        if listeners, ok := eventMgr.listeners; ok {
                for _, listener := range listeners {
                        eventHandler(listener, event, args)
                }
        }
}

func GetInstance() *EventMgr {
        if defaultInstance == nil {
                defaultInstance = &EventMgr{
                        listenerMap: make(mapinterface{}),
                        listeners:   make(mapmapEventHandler),
                        mutex:       &sync.Mutex{},
                        valid:       true,
                }
        }
        return defaultInstance
}

func NewEventMgr(tag interface{}) *EventMgr {
        instanceMutex.Lock()
        defer instanceMutex.Unlock()

        if _, ok := instanceMap; ok {
                LogError(LOG_IDX, LOG_IDX, "NewEventMgr Error: EventMgr %v exist!", tag)
                return nil
        }

        eventMgr := &EventMgr{
                listenerMap: make(mapinterface{}),
                listeners:   make(mapmapEventHandler),
                mutex:       &sync.Mutex{},
                valid:       true,
        }

        if instanceMap == nil {
                instanceMap = make(map*EventMgr)
        }
        instanceMap = eventMgr

        return eventMgr
}

func DeleteEventMgr(tag interface{}) {
        instanceMutex.Lock()
        defer instanceMutex.Unlock()

        if eventMgr, ok := instanceMap; ok {
                eventMgr.mutex.Lock()
                defer eventMgr.mutex.Unlock()

                for k, e := range eventMgr.listenerMap {
                        if emap, ok := eventMgr.listeners; ok {
                                for kk, _ := range emap {
                                        delete(emap, kk)
                                }
                        }
                        delete(eventMgr.listeners, k)
                }
                delete(instanceMap, tag)
        }
}

func GetEventMgrByTag(tag interface{}) (*EventMgr, bool) {
        instanceMutex.Lock()
        defer instanceMutex.Unlock()

        if eventMgr, ok := instanceMap; ok {
                return eventMgr, true
        }
        return nil, false
}

cokeboL 发表于 2016-08-18 15:54

golang还有chan,相当于pipe,或者那个eventfd吧,锁和chan多数场景是可以替换的

cokeboL 发表于 2016-08-18 15:58

本帖最后由 cokeboL 于 2016-08-18 15:59 编辑

因为golang这种,真正做到了多路并发,各路可以顺序编程,不过rpc或者不同模块间,也避免不了需要异步的场景

erlang的进程,太虐心了,进程间通信竟然只能用消息,互不可见,所以当初erlang研究到这个特性的时候,就没有
继续了,erlang这种适合web的场景,用户之间没什么交互,每个连接一个进程,妥妥的。
但是并不适合其他一些交互较多的场景,比如游戏内向全服在线玩家广播,虽然说给所有玩家进程发个msg,每个进程
再发网络包没什么问题,但总感觉比遍历所有连接并send 麻烦,或者一些其他交互的地方,erlang也是鸡肋

yulihua49 发表于 2016-08-18 16:52

嗯。学习一下。要出差了,回来再细看。

cokeboL 发表于 2016-08-18 17:43

回复 28# yulihua49


    好,一路顺利!
页: 1 2 [3] 4
查看完整版本: 事件响应方式