面试题答案
一键面试场景
假设我们从网络读取大量数据,如从远程服务器下载大文件。基于Reader接口实现的网络读取操作,每次调用Read方法可能因为网络延迟等因素,导致频繁的系统调用,从而降低性能。
优化思路
- 使用缓冲区:利用bufio.Reader对原始的Reader进行包装。bufio.Reader内部维护一个缓冲区,它会批量从底层Reader读取数据到缓冲区,这样后续调用Read时,如果缓冲区有数据,就直接从缓冲区读取,减少了系统调用次数。例如:
package main
import (
"bufio"
"fmt"
"io"
"net/http"
)
func main() {
resp, err := http.Get("http://example.com/largefile")
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
// 使用bufio.Reader包装原始的Reader
reader := bufio.NewReader(resp.Body)
buf := make([]byte, 4096)
for {
n, err := reader.Read(buf)
if err != nil && err != io.EOF {
fmt.Println(err)
return
}
if n == 0 {
break
}
// 处理读取到的数据buf[:n]
}
}
- 并发读取:如果有多个数据源可以并行读取,可利用goroutine并发执行读取操作,然后将结果合并。例如,在下载分片存储的文件时,每个分片可以在一个独立的goroutine中读取,最后将各分片数据按顺序合并。不过要注意处理好同步和资源管理问题,防止数据竞争。
- 优化读取策略:根据具体场景调整每次读取的字节数。如果知道数据量大概范围,可以选择合适大小的缓冲区,避免过小的缓冲区导致频繁读取,也避免过大的缓冲区浪费内存。