关于bufio包中Scan方法的疑问

tianlei · 2021-07-10 10:11:08 · 2947 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2021-07-10 10:11:08 的主题,其中的信息可能已经有所发展或是发生改变。

Scan方法中有如下代码片段一

    if s.end > s.start || s.err != nil {
            advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
            if err != nil {
                if err == ErrFinalToken {
                    s.token = token
                    s.done = true
                    return true
                }
                s.setErr(err)
                return false
            }
            .....
}


func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
    if atEOF && len(data) == 0 {
        return 0, nil, nil
    }
    if i := bytes.IndexByte(data, '\n'); i >= 0 {
        // We have a full newline-terminated line.
        return i + 1, dropCR(data[0:i]), nil
    }
    // If we're at EOF, we have a final, non-terminated line. Return it.
    if atEOF {
        return len(data), dropCR(data), nil
    }
    // Request more data.
    return 0, nil, nil
}

此段代码中,s.split实际会调用ScanLines函数,这个函数里面无论如何返回的err都是nil的,这样的话s.split后面的if err != nil是为啥呢。

Scan代码片段二

            const maxInt = int(^uint(0) >> 1)
            if len(s.buf) >= s.maxTokenSize || len(s.buf) > maxInt/2 {
                s.setErr(ErrTooLong)
                return false
            }

这里是buffer满了分配新空间,新空间溢出判断为什么要使用maxInt,在64位windows机器里面,此值是9223372036854775807即便是32位机器也有4294967295,但maxTokenSize在我机器里面仅仅是64 * 1024。为什么要设置一个这么大的值作为上限,内存明显可能不足吧。

请大神指点


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2947 次点击  
加入收藏 微博
4 回复  |  直到 2022-01-06 15:12:56
wuchenghui
wuchenghui · #1 · 4年之前

你的机器太弱了,你可以自己做限制,但是语言层面不能做限制

tianlei
tianlei · #2 · 4年之前
wuchenghuiwuchenghui #1 回复

你的机器太弱了,你可以自己做限制,但是语言层面不能做限制

谢谢指教,语言层面不能做限制的思路我理解了,但是不明白的是,9223372036854775807这个数字是和len(s.buf)比较,那应该是表示byte的长度,约等于8589934591G(9223372036854775807 / 1024 /1024 / 1024)?

yangA7S
yangA7S · #3 · 3年之前

虽然NewScanner里设置的是ScanLines和MaxScanTokenSize,但是split函数可以通过func (s Scanner) Split(split SplitFunc)设置,maxTokenSize可以通过func (s Scanner) Buffer(buf []byte, max int)设置。

正常扫描在for循环的第一个if就退出了,其他则是split没有返回一个非空token,主要是空buf和buf空间不足。可以设置空buf,所以会有一个莫名其妙的startBufSize;buf空间不足,左移数据且扩容,maxInt = int(^uint(0) >> 1),那就是2^31 - 1,maxInt / 2就是2^30,也就是GO限死了最多设置buf为2^30个字节

yangA7S
yangA7S · #4 · 3年之前

MaxScanTokenSize默认16KB,单行超过16KB不是很丧心病狂?

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传