当使用套接字进行工作时,可以重用读取缓冲区。

huangapple go评论124阅读模式
英文:

reusing read buffers when working with sockets

问题

我想知道在Go语言中重用[]byte缓冲区的正确方法。我像这样声明它:

buf := make([]byte, 1024)

然后像这样使用:

conn, _ := net.Dial("tcp", addr)
_, err = conn.Read(buf)

我听说声明一个新的缓冲区并不高效,因为它涉及内存分配,我们应该重用现有的缓冲区。然而,我不确定我是否可以简单地再次传递缓冲区并且它会被清空,还是它可以保存先前消息的部分内容(特别是如果当前来自套接字的消息比先前的消息短)?

英文:

I'd like to know the proper way to reuse the []byte buffer in go. I declare it like this

buf := make([]byte, 1024)

and then use like this

conn, _ := net.Dial("tcp", addr)
_, err = conn.read(buf)

I heard that declaring a new buffer isn't efficient since it involves memory allocations and that we should reuse existing buffers instead. However I am not sure if I just can pass the buffer again and it will be wiped or it can hold parts of previous messages (especially if the current message from socket is shorter than prev.one)?

答案1

得分: 5

Read方法将最多读取len(buf)个字节到缓冲区,并返回读取的字节数。

Read方法不会修改调用者切片的长度。这是因为切片是按值传递的。应用程序必须使用返回的长度来获取实际读取的字节切片。

n, err = conn.Read(buf)
bufRead := buf[:n]

应用程序可以多次调用Read方法,使用相同的缓冲区。

conn, err := net.Dial("tcp", addr)
if err != nil {
    // 处理错误
}

buf := make([]byte, 1024)
for {
    n, err = conn.Read(buf)
    if err != nil {
        // 处理错误
    }
    fmt.Printf("读取 %s\n", buf[:n]) // buf[:n] 是从conn读取的字节切片
}
英文:

The Read method reads up to the len(buf) bytes to the buffer and returns the number of bytes read.

The Read method does not modify length of the caller's slice. It cannot because the slice is passed by value. The application must use the returned length to get a slice of the bytes actually read.

n, err = conn.Read(buf)
bufRead := buf[:n]

The application can call Read multiple times using the the same buffer.

conn, err := net.Dial("tcp", addr)
if err != nil {
    // handle error
}

buf := make([]byte, 1024)
for {
    n, err = conn.Read(buf)
    if err != nil {
        // handle error
    }
    fmt.Printf("Read %s\n", buf[:n]) // buf[:n] is slice of bytes read from conn
}

答案2

得分: 4

在实践中,你很少使用io.Reader.Read(),而是将其传递到代码中需要io.Reader的地方。
缓冲区不会被清除,你必须手动清除它。或者,如果你想要一个缓冲区,你可以使用bufio。

conn, _ := net.Dial("tcp", addr)
r := bufio.NewReader(conn)

你可以这样使用它

r.WriteTo(io.Writer) //例如,用于进一步处理

并且你可以重置

r.Reset(NewConn)
英文:

In practice you rarely use io.Reader.Read(), instead you pipe it down where io.Reader needed in code.
Buffer will not be wiped, you must do it by hand. Or if you want a buffer you can use bufio

conn, _ := net.Dial("tcp", addr)
r:=bufio.NewReader(conn)

which you can

r.WriteTo(io.Writer) //for example for further processing

and you can reset

r.Reset(NewConn)

答案3

得分: 2

> io 包
>
> import "io"
>
> Reader 类型
>
> type Reader interface {
> Read(p []byte) (n int, err error)
> }
>
> Reader 是包装基本 Read 方法的接口。
>
> Read 将最多 len(p) 个字节读入 p 中。它返回读取的字节数(0 <= n <= len(p))和任何遇到的错误。即使 Read 返回的 n < len(p),在调用期间它也可能使用 p 的全部作为临时空间。如果有一些数据可用但不足 len(p) 个字节,Read 通常会返回可用的数据,而不是等待更多数据。
>
> 当 Read 在成功读取 n > 0 个字节后遇到错误或文件结束条件时,它返回读取的字节数。它可能返回相同调用的(非 nil)错误,也可能返回后续调用的错误(和 n == 0)。一个常见情况是,当 Reader 在输入流的末尾返回非零字节数时,它可能返回 err == EOF 或 err == nil。下一次的 Read 应该返回 0, EOF。
>
> 调用者应该在考虑错误 err 之前始终处理返回的 n > 0 个字节。这样做可以正确处理在读取一些字节后发生的 I/O 错误,以及两种允许的 EOF 行为。
>
> Read 的实现应该避免在返回 nil 错误的情况下返回零字节计数,除非 len(p) == 0。调用者应该将返回的 0 和 nil 视为表示什么都没有发生;特别是它不表示 EOF。
>
> 实现必须不保留 p。

在调用期间,Read 可以将整个缓冲区用作临时空间。

例如,

buf := make([]byte, 4096)
for {
    n, err := r.Read(buf[:cap(buf)])
    buf = buf[:n]
    if err != nil {
        // 处理错误
    }
    // 处理 buf
}
英文:

> Package io
>
> import "io"
>
> type Reader
>
> type Reader interface {
> Read(p []byte) (n int, err error)
> }
>
> Reader is the interface that wraps the basic Read method.
>
> Read reads up to len(p) bytes into p. It returns the number of bytes
> read (0 <= n <= len(p)) and any error encountered. Even if Read
> returns n < len(p), it may use all of p as scratch space during the
> call. If some data is available but not len(p) bytes, Read
> conventionally returns what is available instead of waiting for more.
>
> When Read encounters an error or end-of-file condition after
> successfully reading n > 0 bytes, it returns the number of bytes read.
> It may return the (non-nil) error from the same call or return the
> error (and n == 0) from a subsequent call. An instance of this general
> case is that a Reader returning a non-zero number of bytes at the end
> of the input stream may return either err == EOF or err == nil. The
> next Read should return 0, EOF.
>
> Callers should always process the n > 0 bytes returned before
> considering the error err. Doing so correctly handles I/O errors that
> happen after reading some bytes and also both of the allowed EOF
> behaviors.
>
> Implementations of Read are discouraged from returning a zero byte
> count with a nil error, except when len(p) == 0. Callers should treat
> a return of 0 and nil as indicating that nothing happened; in
> particular it does not indicate EOF.
>
> Implementations must not retain p.

Read may use all of the buffer as scratch space during the call.

For example,

buf := make([]byte, 4096)
for {
	n, err := r.Read(buf[:cap(buf)])
	buf = buf[:n]
	if err != nil {
		// handle error
	}
	// process buf
}

huangapple
  • 本文由 发表于 2016年3月19日 22:25:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/36102926.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定