简单聊天室的并发问题

goit · · 1881 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

初学golang,从网上修改了一个聊天室的代码,并发时遇到了一些问题。 ##服务端源码 ``` package main import ( "fmt" "net" "os" "sync" ) var ( readySendCount int sendCount int reciveCount int chanreadySendCount int chansendCount int chanreciveCount int lock sync.Mutex ) func main() { tcpAddr, err := net.ResolveTCPAddr("tcp4", ":9000") if err != nil { os.Exit(1) } server, err := net.ListenTCP("tcp", tcpAddr) if err != nil { os.Exit(1) } conns := make(map[string]net.Conn) messages := make(chan string, 200) go echoHandler(conns, messages) fmt.Println("Listening...") defer server.Close() for { conn, err := server.Accept() if err != nil { os.Exit(1) } lock.Lock() conns[conn.RemoteAddr().String()] = conn lock.Unlock() fmt.Println("new connect :", conn.RemoteAddr().String()) go Handler(conns, conn, messages) } fmt.Println("close") } func Handler(conns map[string]net.Conn, conn net.Conn, messages chan<- string) { buf := make([]byte, 4096) defer conn.Close() for { length, err := conn.Read(buf) if err != nil { break } fmt.Printf("[ %s ] -> %d byte\n", conn.RemoteAddr().String(), length) reciveStr := string(buf[0:length]) readySendCount++ reciveCount++ messages <- reciveStr chanreadySendCount++ chanreciveCount++ } lock.Lock() delete(conns, conn.RemoteAddr().String()) lock.Unlock() } func echoHandler(conns map[string]net.Conn, messages <-chan string) { for { readySendCount-- sendCount++ msg := <-messages chanreadySendCount-- chansendCount++ i := 0 for key, value := range conns { _, err := value.Write([]byte(msg)) if err != nil { lock.Lock() delete(conns, key) lock.Unlock() } else { i++ } } fmt.Printf("send : %d -> %d byte | Queue: %d | ReadySend / Send / All: [ %d / %d / %d ] chan: [ %d / %d / %d ]\n", i, len(msg), len(messages), readySendCount, sendCount, reciveCount, chanreadySendCount, chansendCount, chanreciveCount) } } ``` ##本机测试 100并发测试,每50ms发送1byte数据: ``` send : 0 -> 1 byte | Queue: 5 | ReadySend / Send / All: [ 5 / 81437 / 81442 ] chan: [ -35 / 81437 / 81405 ] send : 0 -> 1 byte | Queue: 4 | ReadySend / Send / All: [ 4 / 81438 / 81442 ] chan: [ -36 / 81438 / 81405 ] send : 0 -> 1 byte | Queue: 3 | ReadySend / Send / All: [ 3 / 81439 / 81442 ] chan: [ -37 / 81439 / 81405 ] send : 0 -> 1 byte | Queue: 2 | ReadySend / Send / All: [ 2 / 81440 / 81442 ] chan: [ -38 / 81440 / 81405 ] send : 0 -> 1 byte | Queue: 1 | ReadySend / Send / All: [ 1 / 81441 / 81442 ] chan: [ -39 / 81441 / 81405 ] send : 0 -> 1 byte | Queue: 0 | ReadySend / Send / All: [ 0 / 81442 / 81442 ] chan: [ -40 / 81442 / 81405 ] ``` 1W并发测试: ``` [ 127.0.0.1:51409 ] -> 181 byte send : 10000 -> 1 byte | Queue: 200 | ReadySend / Send / All: [ 10200 / 81 / 10281 ] chan: [ 200 / 81 / 281 ] [ 127.0.0.1:51244 ] -> 186 byte send : 10000 -> 1 byte | Queue: 200 | ReadySend / Send / All: [ 10200 / 82 / 10282 ] chan: [ 200 / 82 / 282 ] [ 127.0.0.1:50654 ] -> 182 byte send : 10000 -> 1 byte | Queue: 200 | ReadySend / Send / All: [ 10200 / 83 / 10283 ] chan: [ 200 / 83 / 283 ] [ 127.0.0.1:51234 ] -> 186 byte send : 10000 -> 1 byte | Queue: 200 | ReadySend / Send / All: [ 10200 / 84 / 10284 ] chan: [ 200 / 84 / 284 ] ... send : 0 -> 215 byte | Queue: 5 | ReadySend / Send / All: [ 5 / 10314 / 10319 ] chan: [ 4 / 10314 / 10316 ] send : 0 -> 166 byte | Queue: 4 | ReadySend / Send / All: [ 4 / 10315 / 10319 ] chan: [ 3 / 10315 / 10316 ] send : 0 -> 153 byte | Queue: 3 | ReadySend / Send / All: [ 3 / 10316 / 10319 ] chan: [ 2 / 10316 / 10316 ] send : 0 -> 153 byte | Queue: 2 | ReadySend / Send / All: [ 2 / 10317 / 10319 ] chan: [ 1 / 10317 / 10316 ] send : 0 -> 153 byte | Queue: 1 | ReadySend / Send / All: [ 1 / 10318 / 10319 ] chan: [ 0 / 10318 / 10316 ] send : 0 -> 56 byte | Queue: 0 | ReadySend / Send / All: [ 0 / 10319 / 10319 ] chan: [ -1 / 10319 / 10316 ] ``` ##问题 可以发现高并发时chanreciveCount和chanreadySendCount是不准确的,这是什么原因导致的?速度方面,因为聊天室是广播聊天给每一个人,1w在线时每人每秒发一个包,服务端每秒就要发1w^2=1亿个包,不太现实,这种高并发不可能通过简单修改就能实现。

有疑问加站长微信联系(非本文作者)

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

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