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
好,一路顺利!