初学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亿个包,不太现实,这种高并发不可能通过简单修改就能实现。
有疑问加站长微信联系(非本文作者)