127.0.0.1这个IP是不能与127.0.0.1以外的IP进行通讯的,因为127.0.0.1这个IP不经过网络接口,所以只能和本地通信,也就是只能和127.0.0.1进行通信,目的地址和源地址都是127.0.0.1时,程序通过端口在不同的进程间进行通信, 解释下redis绑定127.0.0.1的时候非本机不能访问的案例
1.字节对齐
64位机器默认是8字节对齐的
int32 长度为4, int 在32位os上是4个字节,64位是8个字节
bool 类型虽然只有一位,但也需要占用1个字节,因为计算机是以字节为单位
64为的机器,一个 int 占8个字节
string 类型占16个字节,内部包含一个指向数据的指针(8个字节)和一个 int 的长度(8个字节)
slice 类型占24个字节,内部包含一个指向数据的指针(8个字节)和一个 int 的长度(8个字节)和一个 int 的容量(8个字节)
map 类型占8个字节,是一个指向 map 结构的指针
可以用 struct{} 表示空类型,这个类型不占用任何空间,用这个作为 map 的 value,可以讲 map 当做 set 来用
2.net
2.1 (b *Writer) Flush() 是同步还是异步的?发送缓冲区满了如何?(不报错,继续发?) 发送超时时间?
发送缓冲区满了,不会返回目前已经发送的数据大小,在net库中会返回EAGAIN"阻塞"当前goroutine,直到epoll检查到该socket上有可读信号,比如socket关闭,缓冲区可写等
if err == syscall.EAGAIN && fd.pd.pollable() /usr/local/Cellar/go/1.12.6/libexec/src/internal/poll/fd_unix.go 275行
gopark函数调用了mcall的函数,该函数用汇编来实现,具体功能就是把当前的goroutine挂起,然后去执行其他可执行的goroutine。到这里整个goroutine挂起的过程已经结束,那当goroutine可读的时候是如何通知该goroutine呢,这就是epoll的功劳了。
http://www.opscoder.info/golang_netpoller.html
https://www.jb51.net/article/124602.htm
2.2
timeout本身通过 net.Conn包中的Set[Read|Write]Deadline(time.Time)方法来控制
SetWriteDeadline从设置的时候立即生效,conn超时后不会立即断开, 在发送数据前会对conn做检查: prepareWrite 的时候会直接返回poll.TimeoutError,
而且Writer中也记录了error信息, 个人觉得一旦出现timeout,也不要想着去恢复这个conn了,因为你也不知道究竟写了多少字节数据出去,还是断链重连后重新发送数据包吧
为啥加超时后这么慢,看下addtimer 的实现,timer 是个四叉小顶堆,每次添加一个超时,最后都需要对一个全局的timers 进行加锁,当qps 很高,一个请求,多次加锁,这性能能很高吗?
https://my.oschina.net/u/2950272/blog/2247104?origin=wechat
案例: GoBelieveIO 中 im/connection.go 对读写都设置了超时