英文:
Leaking Reader with tight loop
问题
我有以下代码,我认为它泄漏严重。分析它后,我怀疑 defer r.Close()
从未被调用。
在这里,是否有更好的使用 Reader 和 gzip 的方法?
// 从通道读取客户端数据
func (c *Client) listen() {
timeoutDuration := 30 * time.Second
reader := bufio.NewReader(c.conn)
clientBuffer := new(bytes.Buffer)
for {
c.conn.SetReadDeadline(time.Now().Add(timeoutDuration))
byte, err := reader.ReadByte()
if err != nil {
c.conn.Close()
c.server.onClientConnectionClosed(c, err)
return
}
clientBuffer.WriteByte(byte)
packet := popPacketFromBuffer(clientBuffer)
if packet != nil {
packetBuffer := bytes.NewBuffer(packet)
r, _ := gzip.NewReader(packetBuffer)
defer r.Close()
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
c.server.onNewMessage(c, b)
}
}
}
英文:
I have the following code that I think is leaking heavily. And analysing it I suspect that the defer r.Close()
is never called.
Would there be a better way of using the Reader and gzip here at all?
// Read client data from channel
func (c *Client) listen() {
timeoutDuration := 30 * time.Second
reader := bufio.NewReader(c.conn)
clientBuffer := new(bytes.Buffer)
for {
c.conn.SetReadDeadline(time.Now().Add(timeoutDuration))
byte, err := reader.ReadByte()
if err != nil {
c.conn.Close()
c.server.onClientConnectionClosed(c, err)
return
}
clientBuffer.WriteByte(byte)
packet := popPacketFromBuffer(clientBuffer)
if packet != nil {
packetBuffer := bytes.NewBuffer(packet)
r, _ := gzip.NewReader(packetBuffer)
defer r.Close()
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
c.server.onNewMessage(c, b)
}
}
}
答案1
得分: 3
你的问题是defer
函数只会在函数结束时调用,而不是在循环中调用。所以,是的,它们可能会保持打开状态。
一种方法是将紧密循环封装到一个函数中。
func uncompress(packet []byte) ([]byte, error) {
r, _ := gzip.NewReader(bytes.NewBuffer(packet))
defer r.Close()
return ioutil.ReadAll(r)
}
// 从通道读取客户端数据
func (c *Client) listen() {
/* … */
for {
/* … */
if packet != nil {
b, err := uncompress(packet)
if err != nil {
log.Fatal(err)
}
c.server.onNewMessage(c, b)
}
}
}
另一种方法是展开defer
调用并手动关闭。
// 从通道读取客户端数据
func (c *Client) listen() {
/* … */
for {
/* … */
if packet != nil {
r, _ := gzip.NewReader(bytes.NewBuffer(packet))
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
r.Close()
c.server.onNewMessage(c, b)
}
}
}
英文:
Your problem is that defer
functions are only called at the end of the function. Not the loop. So, yes, it is probable that they stay open.
One method would be to encapsulate your tight-loop into a function.
func uncompress(packet []byte) ([]byte, error) {
r, _ := gzip.NewReader(bytes.NewBuffer(packet))
defer r.Close()
return ioutil.ReadAll(r)
}
// Read client data from channel
func (c *Client) listen() {
/* … */
for {
/* … */
if packet != nil {
b, err := uncompress(packet)
if err != nil {
log.Fatal(err)
}
c.server.onNewMessage(c, b)
}
}
}
Another would be to unroll the defer call and do it manually.
// Read client data from channel
func (c *Client) listen() {
/* … */
for {
/* … */
if packet != nil {
r, _ := gzip.NewReader(bytes.NewBuffer(packet))
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
r.Close()
c.server.onNewMessage(c, b)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论