GO 中高效 int 转换 string 的方法与高性能源码剖析

这篇具有很好参考价值的文章主要介绍了GO 中高效 int 转换 string 的方法与高性能源码剖析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

GO 中高效 int 转换 string 的方法与高性能源码剖析,golang,开发语言,后端


Go 语言 中,将整数(int)转换为字符串(string)是一项常见的操作。

本文将从逐步介绍几种在 Go 中将 int 转换为 string 的常见方法,并重点剖析这几种方法在性能上的特点。另外,还会重点介绍 FormatInt 高效的算法实现。

GO 中高效 int 转换 string 的方法与高性能源码剖析,golang,开发语言,后端

使用 strconv.Itoa

最直接且常用的方法是使用 strconv 包中的 Itoa 函数。Itoa 是 “Integer to ASCII” 的简写,它提供了一种快速且简洁的方式实现整数到字符串之间的转换。

示例代码如下:

package main

import (
    "strconv"
    "fmt"
)

func main() {
    i := 123
    s := strconv.Itoa(i)
    fmt.Println(s)
}

strconv.Itoa 是通过直接将整数转换为其 ASCII 字符串表示形式。这个过程中尽量减少了额外的内存分配,没有复杂逻辑。

使用 fmt.Sprintf

另一种方法是,使用 fmt 包的 Sprintf 函数。这个方法在功能上更为强大和灵活,因为它能处理各种类型并按照指定的格式输出。

示例代码如下:

package main

import (
    "fmt"
)

func main() {
    i := 123
    s := fmt.Sprintf("%d", i)
    fmt.Println(s)
}

虽然 fmt.Sprintf 在功能上非常强大,但它的性能通常不如 strconv.Itoa

为什么呢?

因为 fmt.Sprintf 内部使用了反射(reflection)确定输入值类型,并且在处理过程中涉及到更多的字符串拼接和内存分配。

使用 strconv.FormatInt

当需要更多控制或处理非 int 类型的整数(如 int64)时,可以使用 strconv 包的 FormatInt 函数。

package main

import (
    "strconv"
    "fmt"
)

func main() {
    var i int64 = 123
    s := strconv.FormatInt(i, 10)  // 10 表示十进制
    fmt.Println(s)
}

strconv.FormatInt 提供了对整数转换过程的更细粒度控制,包括 base 的选择(例如,十进制、十六进制等)。

strconv.Itoa 类似,FormatInt 在性能上也非常可观,而且 FormatInt 提供了既灵活又高效的解决方案。

如果我们查看 strconv.Itoa 源码,会发现 strconv.Itoa 其实是 strconv.FormatInt 的一个特殊情况。

// Itoa is shorthand for FormatInt(int64(i), 10).
func Itoa(i int) string {
    return FormatInt(int64(i), 10)
}

现在 int 转 string 的高性能源码剖析,就变成了重点剖析 FormatInt

FormatInt 深入剖析

基于 Go 1.21 版本的 itoa.go 源码,我们可以深入理解 strconv 包中整数到字符串转换函数的高效实现。

func FormatInt(i int64, base int) string {
	if fastSmalls && 0 <= i && i < nSmalls && base == 10 {
		return small(int(i)) // 100 以内的十进制小整数,使用 small 函数转化
	}
  	_, s := formatBits(nil, uint64(i), base, i < 0, false) // 其他情况使用 formatBits
	return s
}

以下是对其核心部分的详细解读,将会突出了其性能优化的关键方面,结合具体的源码实现说明。

GO 中高效 int 转换 string 的方法与高性能源码剖析,golang,开发语言,后端

1. 快速路径处理小整数

对于常见的小整数,strconv 包提供了一个快速路径,small 函数,直接返回预先计算好的字符串,避免了运行时的计算开销。

func small(i int) string {
	if i < 10 {
		return digits[i : i+1]
	}
	return smallsString[i*2 : i*2+2]
}

对于小于 100 的十进制整数,采用这个快速实现方案,或许这也是整数转字符串的最常见使用场景吧。

small 函数通过索引到 smallsStringdigits 获取小整数的字符串表示,这个过程非常快速。

digitssmallsString 的值,如下所示:

const smallsString = "00010203040506070809" +
	"10111213141516171819" +
	"20212223242526272829" +
	"30313233343536373839" +
	"40414243444546474849" +
	"50515253545556575859" +
	"60616263646566676869" +
	"70717273747576777879" +
	"80818283848586878889" +
	"90919293949596979899"

const digits = "0123456789abcdefghijklmnopqrstuvwxyz"

它们也就是十进制 0-99 与对应字符串的映射。

2. formatBits 函数的高效实现

FormatInt 最复杂的部分是 formatBits 函数,它是整数到字符串转换的核心,它针对不同的基数进行了优化。

GO 中高效 int 转换 string 的方法与高性能源码剖析,golang,开发语言,后端

10进制转换的优化

对于10进制转换,formatBits 使用了基于除法和取余的算法,并通过 smallsString 加速两位数的字符串获取。

if base == 10 {
	// ... (32位系统的优化)
	us := uint(u)
	for us >= 100 {
		is := us % 100 * 2
		us /= 100
		i -= 2
		a[i+1] = smallsString[is+1]
		a[i+0] = smallsString[is+0]
	}
	// ... (处理剩余的数字)
}
  • 对于 32 位系统,使用32位操作处理较大的数字,减少 64 位除法的开销。
  • 每次处理两位数字,直接从 smallsString 获取对应的字符,避免了单独转换每一位的开销。

2的幂基数的优化

对于基数是2的幂的情况,formatBits 使用了位操作来优化转换。

} else if isPowerOfTwo(base) {
	shift := uint(bits.TrailingZeros(uint(base))) & 7
	b := uint64(base)
	m := uint(base) - 1 // == 1<<shift - 1
	for u >= b {
		i--
		a[i] = digits[uint(u)&m]
		u >>= shift
	}
	// u < base
	i--
	a[i] = digits[uint(u)]
}
  • 位操作是直接在二进制上进行,比除法和取余操作更快。
  • 利用 2 的幂基数的特性,通过移位和掩码操作获取数字的各个位。

通用情况的处理

对于其他基数,formatBits 使用了通用的算法,但仍然尽量减少了除法和取余操作的使用。

} else {
	// general case
	b := uint64(base)
	for u >= b {
		i--
		// Avoid using r = a%b in addition to q = a/b
		// since 64bit division and modulo operations
		// are calculated by runtime functions on 32bit machines.
		q := u / b
		a[i] = digits[uint(u-q*b)]
		u = q
}

我觉得最核心的算法就是利用移位和特殊路径预置映射关系。另外,由于算法足够优秀,还避免了一些不必要内存分配。

结论

将 int 转化为 string 是一个非常常见的需求。Go 语言的 strconv 包中的 int 到 string 的转换函数展示了 Go 标准库对性能的深刻理解和关注。

通过快速处理小整数、优化的 10 进制转换算法、以及2^n 基数的特别处理,这些函数能够提供高效且稳定的性能。这些优化确保了即使在大量数据或在性能敏感的场景中,strconv 包的函数也能提供出色的性能

博文地址:GO 中高效 int 转换 string 的方法与源码剖析文章来源地址https://www.toymoban.com/news/detail-811744.html

到了这里,关于GO 中高效 int 转换 string 的方法与高性能源码剖析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中将String类型转换为int类型的方法

    在Java编程中,经常需要将字符串类型(String)转换为整数类型(int)。这在处理用户输入、读取文件或进行数值计算时非常常见。本文将详细介绍如何在Java中进行这种类型转换,并提供相应的源代码示例。 Java提供了几种方法来实现String到int的转换。下面将介绍其中的两种常

    2024年02月05日
    浏览(87)
  • Java 中将 String 类型转换为 int 类型的方法

    在Java中将 String 类型转换为 int 类型是一个常见的操作,因为在实际开发中,我们经常需要从用户输入或者外部数据源中获取字符串形式的数字,并将其转换为整数进行计算和处理。在Java中,有几种方法可以实现这种转换,下面我将逐一介绍这些方法。 Integer.parseInt() 方法是

    2024年04月22日
    浏览(49)
  • 《高性能MySQL》——创建高性能的索引(笔记)

    索引(在MySQL中也叫做“键(key)”) 是存储引擎用于快速找到记录的一种数据结构。 索引对于良好的性能非常关键。尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要。 在数据量较小且负载较低时,不恰当的索引对性能的影响可能还不明显,但当数据量逐渐增大时

    2024年02月07日
    浏览(112)
  • 【Linux高性能服务器编程】——高性能服务器框架

      hello !大家好呀! 欢迎大家来到我的Linux高性能服务器编程系列之高性能服务器框架介绍,在这篇文章中, 你将会学习到高效的创建自己的高性能服务器,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!! 希望这篇

    2024年04月25日
    浏览(56)
  • 读高性能MySQL(第4版)笔记09_创建高性能索引(下)

    1.4.4.1. InnoDB的二级索引在叶子节点中保存了记录的主键值,所以如果二级索引能够覆盖查询,则可以避免对主键索引的二次查询 7.1.5.1. 常见的类似错误通常是由于尝试使用rsync备份InnoDB导致的 7.3.3.1. 否则,对于范围查询、索引覆盖扫描等操作来说,速度可能会降低很多 7

    2024年02月08日
    浏览(59)
  • 读高性能MySQL(第4版)笔记08_创建高性能索引(上)

    2.4.2.1. 按照索引列中的数据大小顺序存储的 2.4.3.1. 键前缀查找只适用于根据最左前缀的查找 2.4.4.1. 在查询某些条件的数据时,存储引擎不再需要进行全表扫描 2.4.4.2. 通过比较节点页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点页中

    2024年02月08日
    浏览(47)
  • 《高性能MYSQL》-- 查询性能优化

    查询性能优化 深刻地理解MySQL如何真正地执行查询,并明白高效和低效的原因何在 查询的生命周期(不完整):从客户端到服务器,然后服务器上进行语法解析,生成执行计划,执行,并给客户端返回结果。 一条查询,如果查询得很慢,原因大概率是访问的数据太多 对于低

    2024年03月11日
    浏览(71)
  • 如何在C++中将int类型的变量转换为string类型呢?今天我们就来介绍两种方法。

    如何在C++中将int类型的变量转换为string类型呢?今天我们就来介绍两种方法。 第一种方法是使用C++11标准引入的std::to_string()函数。这个函数可以将数字类型的变量转换为对应的字符串类型。下面是一个使用示例: 上面的代码将整型变量num转换为字符串类型,并输出到控制台

    2024年02月08日
    浏览(54)
  • 《高性能MySQL》——查询性能优化(笔记)

    将查询看作一个任务,那么它由一系列子任务组成,实际我们所做的就是: 消除一些子任务 减少子任务的执行次数 让子任务运行更快 查询的生命周期大概可分为 = { 客户端 服务器 : 进行解析 , 生成执行计划 执行:包括到存储引擎的调用,以及用后的数据处理 { 排序 分组

    2024年02月13日
    浏览(52)
  • 高性能MySQL实战(三):性能优化

    大家好,我是 方圆 。这篇主要介绍对慢 SQL 优化的一些手段,而在讲解具体的优化措施之前,我想先对 EXPLAIN 进行介绍,它是我们在分析查询时必要的操作,理解了它输出结果的内容更有利于我们优化 SQL。为了方便大家的阅读,在下文中规定类似 key1 的表示二级索引,key_

    2024年02月11日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包