0

0

Go String 解析

Guanhui

Guanhui

发布时间:2020-06-12 18:21:23

|

3408人浏览过

|

来源于learnku

转载

Go String 解析

什么是字符串?

在 Go 中,字符串是一个 (可能为空) 不可变的字节序列。对于我们来说,这里的关键词是 不可变。因为字节片是可变的,所以在 string 和 []byte 之间进行转换通常需要分配和复制,这是很昂贵的。

在幕后,Go 的字符串 (当前) 表示为 长度和指向字符串数据的指针.

什么是字符串驻留?

考虑这段代码:

b := []byte("hello")
s := string(b)
t := string(b)

s 和 t 是字符串,因此它们都有长度和数据指针。它们的长度显然是相同的。那它们的数据指针呢?

Go 语言无法为我们提供直接的查找方法。但是我们可以使用 unsafe 来探查:

func pointer(s string) uintptr {
    p := unsafe.Pointer(&s)
    h := *(*reflect.StringHeader)(p)
    return h.Data
}

(此函数应返回 unsafe.Pointer。详见 Go 问题 19367。)

如果我们 fmt.Println(pointer(s), pointer(t)),我们会得到类似 4302664 4302632 的信息。指针是不同的;它们有两个单独的数据副本 hello。

(这是一个练习链接。如果你想要尝试,将 "hello" 变成 "h" 会发生什么情况?解释  )

假设您希望重新使用数据 hello 的单个副本?这就是字符串驻留。字符串驻留有两个优点。明显的一个优点是,你不需要分配和复制数据。另一个优点是它加快了字符串相等性检查的速度。如果两个字符串具有相同的长度和相同的数据指针,则它们是相等的;没有必要检查字节。

从 Go 1.14 开始,Go 不会驻留大多数字符串。与其它形式的缓存一样,驻留也有成本:并发安全性的同步,垃圾收集器的复杂性,以及每次创建字符串时要执行的额外代码。而且,就像缓存一样,在某些情况下它是有害的,而不是有用的。如果你在处理字典里的单词,则任何单词都不会出现两次,这时,字符串驻留既浪费时间又浪费内存。

手动字符串驻留

可以在 Go 中手动驻留字符串。我们需要的是一种在给定字节切片 (byte slice) 的情况下寻找现有字符串以重新使用的方法,也许使用诸如 map[[]byte]string 之类的方法。如果查找成功,则使用现有字符串;如果失败,我们将转换并存储该字符串以备将来使用。

Memories.ai
Memories.ai

专注于视频解析的AI视觉记忆模型

下载

这里只有一个问题:您不能使用 []byte 作为 map 的键。

多亏了长期的编译器优化,我们可以使用 map[string]string 代替。这里有一个优化,键是转换后字节切片的 map 操作实际上不会生成在查找期间会用到的新字符串。

m := make(map[string]string)
b := []byte("hello")
s := string(b) // 分配了
_ = m[string(b)] // 不分配!

(类似的优化适用于其他情况,在这些情况下,编译器可以证明转换后的字节切片在使用过程中不会被修改,例如 switch string(b),当所有 switch 情况都没有副作用时。)

驻留字符串所需的全部代码是这样的:

func intern(m map[string]string, b []byte) string {
    // 查找一个存在的字符串来重用
    c, ok := m[string(b)]
    if ok {
        // 找到一个存在的字符串
        return c
    }
    // 没有找到,所以制作一个并且存储它
    s := string(b)
    m[s] = s
    return s
}

很简单

新出现的困难(并发症)

请注意,这个手动驻留例程将驻留问题推入了调用代码。您需要管理对 map 的并发访问;您需要确定 map (以及其中的所有内容) 的生命周期;并且您每次需要字符串时都需要付出 map 查找的额外费用。

将这些决定推到调用代码上可以产生更好的性能。例如,假设您正在将 json 解码为 map[string]interface{}。json 解码器可能不是并发的。map 的生命周期可以绑定到 json 解码器。并且此 map 的键很可能会经常重复,这是字符串驻留的最佳情况;这使得额外的 map 查找成本值得。

一个助手包

如果您不想考虑这些并发症中的任何一个,并且愿意接受轻微的性能损失,并且有字符串驻留可能会有所帮助的代码,则有一个为此的包:github.com/josharian/intern。

它的工作原理是可怕的滥用 sync.Pool。它将驻留 maps 存储在 sync.Pool 中,根据需要检索它们。这很好的解决了并发访问问题,因为 sync.Pool 的访问是并发安全的。它主要解决了生存期问题,因为在 sync.Pool 中的内容通常最终会被垃圾收集。(有关管理生存期的相关阅读,请参阅 Go issue 29696。)

推荐教程:《PHP》《GO教程

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2594

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1621

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1508

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

952

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1417

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1234

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1447

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1306

2023.11.13

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

23

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
golang socket 编程
golang socket 编程

共2课时 | 0.1万人学习

nginx浅谈
nginx浅谈

共15课时 | 0.8万人学习

golang和swoole核心底层分析
golang和swoole核心底层分析

共3课时 | 0.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号