本文原创文章,转载注明出处,博客地址 https://segmentfault.com/u/to... 第一时间看后续精彩文章。觉得好的话,顺手分享到朋友圈吧,感谢支持。

Go中可以使用“+”合并字符串,但是这种合并方式效率非常低,每合并一次,都是创建一个新的字符串,就必须遍历复制一次字符串。Java中提供StringBuilder类(最高效,线程不安全)来解决这个问题。Go中也有类似的机制,那就是Buffer(线程不安全)。

以下是示例代码:
package mainimport ("bytes""fmt"
)func main() {var buffer bytes.Bufferfor i := 0; i < 1000; i++ {buffer.WriteString("a")}fmt.Println(buffer.String())
}

使用bytes.Buffer来组装字符串,不需要复制,只需要将添加的字符串放在缓存末尾即可。

Buffer为什么线程不安全?

The Go documentation follows a simple rule: If it is not explicitly stated that concurrent access to something is safe, it is not.

==Go文档遵循一个简单的规则:如果没有明确声明并发访问某事物是安全的,则不是。==

以下是Golang中bytes.Buffer部分源码
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {buf       []byte   // contents are the bytes buf[off : len(buf)]off       int      // read at &buf[off], write at &buf[len(buf)]bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.lastRead  readOp   // last read operation, so that Unread* can work correctly.
}// Write appends the contents of p to the buffer, growing the buffer as
// needed. The return value n is the length of p; err is always nil. If the
// buffer becomes too large, Write will panic with ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) {b.lastRead = opInvalidm := b.grow(len(p))return copy(b.buf[m:], p), nil
}// Read reads the next len(p) bytes from the buffer or until the buffer
// is drained. The return value n is the number of bytes read. If the
// buffer has no data to return, err is io.EOF (unless len(p) is zero);
// otherwise it is nil.
func (b *Buffer) Read(p []byte) (n int, err error) {b.lastRead = opInvalidif b.off >= len(b.buf) {// Buffer is empty, reset to recover space.b.Truncate(0)if len(p) == 0 {return}return 0, io.EOF}n = copy(p, b.buf[b.off:])b.off += nif n > 0 {b.lastRead = opRead}return
}

源码对于Buffer的定义中,并没有关于锁的字段,在write和read函数中也未发现锁的踪影,所以符合上面提到的文档中的rule,即Buffer并发是不安全的

如何自定义实现一个并发安全的Buffer

type Buffer struct {b bytes.Bufferrw sync.RWMutex
}
func (b *Buffer) Read(p []byte) (n int, err error) {b.rw.RLock()defer b.rw.RUnlock()return b.b.Read(p)
}
func (b *Buffer) Write(p []byte) (n int, err error) {b.rw.Lock()defer b.rw.Unlock()return b.b.Write(p)
}

通过读写锁,解决并发读写问题,以上提供了Read和Write函数,亲,是不是Golang代码简洁明了?其它函数可以在Golang关于Buffer源码的基础上自行实现

两种锁的区别
sync.Mutex(互斥锁) sync.RWMutex(读写锁)
当一个goroutine访问的时候,其他goroutine都不能访问,保证了资源的同步,避免了竞争,不过也降低了性能 非写状态时:多个Goroutine可以同时读,一个Goroutine写的时候,其它Goroutine不能读也不能写,性能好

Golang中Buffer高效拼接字符串以及自定义线程安全Buffer相关推荐

  1. golang 包含 数组_在 Golang 中如何快速判断字符串是否在一个数组中

    在使用 Python 的时候,如果要判断一个字符串是否在另一个包含字符串的列表中,可以使用in 关键词,例如: name_list= ['pm', 'kingname', '青南'] if 'king ...

  2. 在 Golang 中如何快速判断字符串是否在一个数组中

    在使用 Python 的时候,如果要判断一个字符串是否在另一个包含字符串的列表中,可以使用in 关键词,例如: name_list = ['pm', 'kingname', '青南'] if 'kin ...

  3. oracle拼接字符串报错,Oracle 中wmsys.wm_concat拼接字符串,结果过长报错解决

    备忘:这个函数最大是4000,根据拼接列的长度,通过限制拼接条数来防止拼接字符串过长错误 --这个情况是从子表中读取出具,这里直接把它当做查询字段处理,在子表中有所有数据 select info.id ...

  4. golang中ascll和string字符串的相互转化

    文章目录 背景 ascll 码转字符/string 字符转 ascll 码 string 转 ascll 码 背景 ascll 码转化方面和 java 很不相同,golang 中的字符分为 rune ...

  5. java字符串怎么拼接字符串_Java中String使用+ 拼接字符串的原理是什么?

    来看一段代码 public class Test { String str1 = "51"; String str2 = "manong"; String st ...

  6. shell中for循环拼接字符串

    # 使用场景 通过shell脚本传参指定表名.分区字段和普通字段导入数据到hive表 # sh test.sh a b c d e f # 输出 d,e,f # 在当前目录下创建文本文件temp,如果 ...

  7. JavaScript中大量拼接字符串的方法

    由于js中字符串的不可变性 使得我们在使用+=拼接字符串的时候会占用很大的空间,容易造成卡死情况 接下来是解决方法 <script>//如果我们大量使用+=进行字符串拼接的话,将会使界面失 ...

  8. golang中的字符串拼接

    go语言中支持的字符串拼接的方法有很多种,这里就来罗列一下 常用的字符串拼接方法 1.最常用的方法肯定是 + 连接两个字符串.这与python类似,不过由于golang中的字符串是不可变的类型,因此用 ...

  9. Java中如何高效的拼接字符串

    目录 写在前面 常规的字符串拼接方法 写在前面 这是一篇非常基础的文章,将会演示如何使用Java正确高效的拼接字符串. 这些问题也是我们应该注意的基础的性能优化技巧. 常规的字符串拼接方法 使用'+' ...

最新文章

  1. linux平台调试终端,10款Linux平台上优秀的调试器,总有一款适合你!
  2. 循环求100内质数 php_C8循环
  3. python基础知识理解
  4. 泽泽计算机科技,《计算机与信息技术》大学技能学习丛书.pdf
  5. 图本检索的Zero-Shot超过CLIP模型!FILIP用细粒度的后期交互获得更好的预训练效率。...
  6. 李萍matlab实验报告,李萍, 张磊, 王垚廷. 基于Matlab的偏微分方程数值计算[J]. 齐鲁工业大学学报, 2017, 31(4): 39-43....
  7. 低姿态生活,高境界做人
  8. vivado global和out-of-context 选项
  9. laravel 核心类Kernel
  10. yaahp使用教程_yaahp层次分析法软件
  11. 机械臂动力学建模(2)- Kane凯恩算法
  12. 小米手机助手linux,小米手机助手怎么用?小米手机助手教程
  13. xshell修改服务器登录密码
  14. aspcms用mysql_关于ASPCMS标签调用的一些总结
  15. 电脑打开网络没有WiFi列表
  16. krait和kryo_HBase和Kryo混合使用时出现的jar包冲突
  17. rest接口案例_REST和平:微服务与现实案例中的整体
  18. 工艺角,PVT, TT,SS,FF,FS,SF
  19. 《灵飞经》3·印神无双 第十三章 剑奕星斗 2
  20. 电影《蓝色大门》有感

热门文章

  1. Android定位方式和测试方法
  2. 二进制,十进制,十六进制
  3. 关于层的挡隔问题的探讨
  4. Git简介以及与SVN的区别
  5. matlab图像处理命令(一)
  6. 服务器性能好的笔记本电脑,2020高性价比笔记本推荐-1万以上笔记本电脑排行
  7. 用友u8 php,php 访问用友u8数据
  8. vmware响应时间过长_性能调优高并发下如何缩短响应时间
  9. django model filter_Django框架使用流程(四)
  10. 没有什么效果的html标签,你知道却不常用的HTML标签(一)