https://groups.google.com/forum/#!topic/golang-nuts/I7a_3B8_9Gw

https://groups.google.com/forum/#!msg/golang-nuts/coc6bAl2kPM/ypNLG3I4mk0J

ask:   -----------------------

Hello,

I'm curious as to what the proper way of listening multiple simultaneous sockets is?
Please consider the two implementations I currently have: http://play.golang.org/p/LOd7q3aawd
 
Receive1 is a rather simple implementation, spawning a goroutine per connection, and simply blocking on each one via the ReadFromUDP method of the connection.
Receive2 is a more C-style approach, using the real select to block until either one of the sockets actually receives something, and then actually trying to read.
 
Now, Receive2 is _supposedly_ better, since we rely on the kernel to notify the select if one of the file descriptors is ready for reading. That would, under ideal conditions (and maybe less goroutines), allow the process itself to fall asleep until data starts pouring into the socket.
Receive1 is relying on the I/O read blocking until something comes along, and is doing so for each connection. Or at least that's what my understanding is, I'm not sure whether internally, the connection is still using select. Though even if it was, I don't thing the go scheduler is smart enough to put the whole process to sleep if two separate goroutines are waiting for I/O. That being said, Receive1 looks so much better than its counterpart.
 
If there is also a better way than either of these, please share it with me.
 
 
answer1:   ------------------------------------------
Recieve1 is better. Go will use asynchronous I/O (equivalent to select) under the covers for you. The go scheduler is smart enough to "put the whole process to sleep if [all] goroutines are waiting for I/O". Don't worry about it. Just use idiomatic Go.
 
answer2:   ------------------------------------------
Receive1 is certainly the Go way. I wonder however why you need to read from two UDP ports. UDP is connectionless, so you can support multiple clients with one open UDP port.

 

That being said you should know that any goroutine blocking in a system call consumes one kernel thread. This will not be a problem until you need to support thousands of connections. But at this scale the file descriptor bitmaps used by select become a performance bottleneck as well. In this situation you might want to look at epoll on Linux. On other systems poll might be an alternative. If you are in this territory I strongly recommend to have a look into Michael Kerrisk's excellent reference "The LINUX Programming Interface".

 
answer3:   ------------------------------------------
It's true that a goroutine blocking in a syscall consumes a kernel thread. However, Receive1 will *not* use any kernel threads while waiting in conn.ReadFromUDP, because under the covers, the Go runtime uses nonblocking I/O for all network activity. It's much better just to rely on the runtime implementation of network I/O rather than trying to roll your own. If you don't believe me, try doing syscall traces or profiling to prove it out.
 
answer4:   ------------------------------------------
receive2 approach is not portable (due to syscall), and is more complex. also, unless profiling can prove it, efficiency of the approach is a speculation.
 
answer5:   ------------------------------------------
Matt, thank you I learned something. During network access the Goroutine is not blocked in a syscall and Go is already using epoll internally. So unless you know what you are doing the Goroutine approach will work best.
 
 
这个问答中的 example code:
package main

import (
"fmt"
"net"
"os"
"syscall"
) func Receive1(conn1, conn2 *net.UDPConn, done chan struct{}) <-chan string {
res := make(chan string)
tokenChan := make(chan []string) for _, conn := range []*net.UDPConn{conn1, conn2} {
go func(conn *net.UDPConn) {
buf := make([]byte, )
for {
select {
case <-done:
return
default:
if n, _, err := conn.ReadFromUDP(buf); err == nil {
fmt.Println(string(buf[:n]))
res <- string(buf[:n])
}
}
}
}(conn)
} return res
} func Receive2(conn1, conn2 *net.UDPConn, done chan struct{}) <-chan string {
res := make(chan string)
fds := &syscall.FdSet{}
filemap := map[int]*os.File{}
var maxfd =
for _, conn := range []*net.UDPConn{conn1, conn2} {
if file, err := conn.File(); err == nil {
fd := int(file.Fd())
FD_SET(fds, fd)
filemap[fd] = file
if fd > maxfd {
maxfd = fd
}
}
} go func() {
for {
select {
case <-done:
return
default:
fdsetCopy := *fds
tv := syscall.Timeval{, }
if _, err := syscall.Select(maxfd+, &fdsetCopy, nil, nil, &tv); err == nil {
for fd, file := range filemap {
if !FD_ISSET(&fdsetCopy, fd) {
continue
} buf := make([]byte, )
if n, err := file.Read(buf); err == nil {
fmt.Println(string(buf[:n]))
res <- string(buf[:n])
}
}
}
}
}
}() return res
} func FD_SET(p *syscall.FdSet, i int) {
p.Bits[i/] |= << (uint(i) % )
} func FD_ISSET(p *syscall.FdSet, i int) bool {
return (p.Bits[i/] & ( << (uint(i) % ))) !=
} func main() {
fmt.Println("Hello, playground")
}
 
 
ask:  -------------------------------
Hello,
It is said that event-driven nonblocking model is not the preferred programming model in Go, so I use "one goroutine for one client" model, but is it OK to handle millions of concurrent goroutines in a server process?
 
And, how can I "select" millions of channel to see which goroutine has data received? The "select" statement can only select on predictable number of channels, not on a lot of unpredictable channels. And how can I "select" a TCP Connection (which is not a channel) to see if there is any data arrived? Is there any "design patterns" on concurrent programming in Go?
Thanks in advance.
 
answer: ----------------------------------

Hello,
 
It
is said that event-driven nonblocking model is not the preferred
programming model in Go, so I use "one goroutine for one client" model,
but is it OK to handle millions of concurrent goroutines in a server
process?
 

A goroutine itself is
4kb. So 1e6 goroutines would require 4gb of base memory. And then
whatever your server needs per goroutine that you add.

 
Any machine that might be handling 1e6 concurrent connections should have well over 4gb of memory. 
 
And, how can I "select" millions of channel to see which goroutine has data received?
 
That's
not how it works. You just try to .Read() in each goroutine, and the
select is done under the hood. The select{} statement is for channel
communication, specifically.
 
All IO in go is
event driven under the hood, but as far as the code you write, looks
linear. The Go runtime maintains a single thread that runs epoll or
kqueue or whatever under the hood, and wakes up a goroutine when new
data has arrived for that goroutine. 
 
The
"select" statement can only select on predictable number of channels,
not on a lot of unpredictable channels. And how can I "select" a TCP
Connection (which is not a channel) to see if there is any data arrived?
Is there any "design patterns" on concurrent programming in Go?
 
These problems you anticipate simply do not exist with go. Give it a shot!
 
 
 

golang 中处理大规模tcp socket网络连接的方法,相当于c语言的 poll 或 epoll的更多相关文章

  1. inux中,关于多路复用的使用,有三种不同的API,select、poll和epoll

    inux中,关于多路复用的使用,有三种不同的API,select.poll和epoll https://www.cnblogs.com/yearsj/p/9647135.html 在上一篇博文中提到了 ...

  2. 在c#中利用keep-alive处理socket网络异常断开的方法

    本文摘自 http://www.z6688.com/info/57987-1.htm 最近我负责一个IM项目的开发,服务端和客户端采用TCP协议连接.服务端采用C#开发,客户端采用Delphi开发.在 ...

  3. CentOS下netstat + awk 查看tcp的网络连接状态

    执行以下命令: #netstat -n | awk ‘/^tcp/ {++state[$NF]} END {for(key in state) print key."\t".sta ...

  4. 【虚拟机】在VMware中安装Server2008之后配置网络连接的几种方式

    VMware虚拟机的网络连接方式分为三种:桥接模式.NAT模式.仅主机(Host Only) (1)桥接模式 桥接模式即在虚拟机中虚拟一块网卡,这样主机和虚拟机在一个网段中就被看作是两个独立的IP地址 ...

  5. socket 网络连接基础

    socket 客户端 import socket 1.client = socket.socket()  # socket.TCP/IP 选择连接的类型,默认为本地连接 2.client.connec ...

  6. VC:检测网络连接的方法

    方法一: #include "stdafx.h" #include "windows.h" #include <Sensapi.h> #includ ...

  7. golang中浮点型底层存储原理和decimal使用方法

    var price float32 = 39.29 float64和float32类似,只是用于表示各部分的位数不同而已,其中:sign=1位,exponent=11位,fraction=52位,也就 ...

  8. 服务器中判断客户端socket断开连接的方法

    1, 如果服务端的Socket比客户端的Socket先关闭,会导致客户端出现TIME_WAIT状态,占用系统资源. 所以,必须等客户端先关闭Socket后,服务器端再关闭Socket才能避免TIME_ ...

  9. 服务器中判断客户端socket断开连接的方法【转】

    本文转载自:http://www.cnblogs.com/jacklikedogs/p/3976208.html 1, 如果服务端的Socket比客户端的Socket先关闭,会导致客户端出现TIME_ ...

随机推荐

  1. postmain 通过函数动态设置参数

    调用服务器的服务,其中有个参数是签名,签名需要计算,需要写一个本地函数. 下一步 pre-request Script 的代码如下: (function($) { if(!$.encoding) $. ...

  2. Ubuntu下配置使用mysql

    很多生产环境都使用linux系统,相比于window系统,界面真的做的不够人性化,但是简洁高效也是linux的优点吧.在linux上使用mysql又是不一样的风景吧.

  3. RabbitMQ----整理

    ------------------------------------------------------------------RabbitMQ-------------------------- ...

  4. tomcat项目启动报错java.lang.ClassCastException: org.apache.xerces.parsers.XML11Configuration……

    周一上班启动项目,报错如图: 看到网上说的原因,有jar包冲突造成的,我这里的是: 情况:console打印信息有多次连接数据库,但该项目只需要连接一个库.再仔细看,发现有其他项目的信息,打开tomc ...

  5. TOP100summit:【分享实录-美团点评】 业务快速升级发展背后的系统架构演进

    本篇文章内容来自2016年TOP100summit美团●大众点评高级技术专家,酒店后台研发组eHome团队负责人许关飞的案例分享.编辑:Cynthia 许关飞:美团●大众点评高级技术专家,酒店后台研发 ...

  6. AtCoder Beginner Contest 070|Elena|8.12|#471

    打了场beginner的AtCoder,也是我第一次打AtCoder,虽然AK了,但是由于手速慢+撒比,才#471… 比赛链接:https://beta.atcoder.jp/contests/abc ...

  7. docker swarm:执行 service update 过程中服务短暂不能访问的问题

    这是我们使用自建 docker swarm 集群后在部署时遇到的一个问题,使用 docker service update 命令更新服务时, docker service update -d=fals ...

  8. vim中的ctrl+s导致的“假死”、无响应、不接受输入

    有时候vim看到vim的光标在闪烁,但无法输入任何东西,最后只好结束终端了事. 这种现象,是windows用户在使用vim时经常犯的“错误”.在windows下,为了保护自己的劳动成果,ctrl+s已 ...

  9. [No000010B]Git4/9-时光机穿梭

    我们已经成功地添加并提交了一个readme.txt文件,现在,是时候继续工作了,于是,我们继续修改readme.txt文件,改成如下内容: Git is a distributed version c ...

  10. [daily][cgroup] 使用cgroup限制进程的CPU占用

    参考: https://segmentfault.com/a/1190000008323952 1. 找到cgroup设置的地方. [root@D128 ~]# mount -l |grep cpu ...