Go 如何将一种数值类型的切片转换为另一种类型
我正在试验围棋语言,我对它很陌生。我已经成功地完成了教程,现在正在编写一个小程序,以评估我通常执行的操作类型的性能。我有一个很长的float32类型的切片,需要尽可能高效地将其转换为float64类型的切片。除了迭代切片的元素并通过输出[i]=float64(数据[i])显式转换单个元素的类型外,是否有一种方法可以用于转换整个切片而无需迭代?我尝试过搜索一个解决方案,但没有找到任何直接相关的解决方案。Go的级别非常低,这意味着迭代切片是最有效的方法。其他语言可能有用于这些事情的内置函数,但它们所做的只是通过切片进行迭代,没有迭代就无法完成。但是有一些技巧,特别是使用范围和避免索引切片,因为越界检查中存在开销。这将是最有效的:Go 如何将一种数值类型的切片转换为另一种类型,go,Go,我正在试验围棋语言,我对它很陌生。我已经成功地完成了教程,现在正在编写一个小程序,以评估我通常执行的操作类型的性能。我有一个很长的float32类型的切片,需要尽可能高效地将其转换为float64类型的切片。除了迭代切片的元素并通过输出[i]=float64(数据[i])显式转换单个元素的类型外,是否有一种方法可以用于转换整个切片而无需迭代?我尝试过搜索一个解决方案,但没有找到任何直接相关的解决方案。Go的级别非常低,这意味着迭代切片是最有效的方法。其他语言可能有用于这些事情的内置函数,但它们所
func convertTo64(ar []float32) []float64 {
newar := make([]float64, len(ar))
var v float32
var i int
for i, v = range ar {
newar[i] = float64(v)
}
return newar
}
slice32 := make([]float32, 1000)
slice64 := convertTo64(slice32)
请注意,在范围循环中使用
:=
效率低下,因为在当前版本的Go中,变量会被丢弃并每次重新创建,而不是重复使用。对于i=0,使用range
代替;我对性能声明持怀疑态度总是明智的。例如,“在范围循环中使用:=将是低效的,因为每次都会丢弃并重新创建变量,而不是重复使用。”
让我们看看连续三次运行的基准测试结果
浮动\u测试。转到
:
package main
import "testing"
var slice64 []float64
func FuncVar(f32 []float32) []float64 {
f64 := make([]float64, len(f32))
var f float32
var i int
for i, f = range f32 {
f64[i] = float64(f)
}
return f64
}
func BenchmarkFuncVar(b *testing.B) {
f32 := make([]float32, 1024)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
slice64 = FuncVar(f32)
}
}
func RangeVar(f32 []float32) []float64 {
f64 := make([]float64, len(f32))
for i, f := range f32 {
f64[i] = float64(f)
}
return f64
}
func BenchmarkRangeVar(b *testing.B) {
f32 := make([]float32, 1024)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
slice64 = RangeVar(f32)
}
}
func main() {}
主程序包
导入“测试”
var slice64[]float64
func FuncVar(f32[]float32][]float64{
f64:=make([]浮点64,len(f32))
变量f浮动32
变量i int
对于i,f=范围f32{
f64[i]=64(f)
}
返回f64
}
func BenchmarkFuncVar(b*testing.b){
f32:=make([]32,1024)
b、 ReportAllocs()
b、 重置计时器()
对于i:=0;i
输出:
$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar 100000 12260 ns/op 8192 B/op 1 allocs/op
BenchmarkRangeVar 100000 12125 ns/op 8192 B/op 1 allocs/op
ok so/test 2.703s
$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar 100000 12620 ns/op 8192 B/op 1 allocs/op
BenchmarkRangeVar 100000 12623 ns/op 8192 B/op 1 allocs/op
ok so/test 2.782s
$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar 100000 12730 ns/op 8192 B/op 1 allocs/op
BenchmarkRangeVar 100000 12971 ns/op 8192 B/op 1 allocs/op
ok so/test 2.852s
$
$ go build floata.go && ./floata
FuncVar 10.479653966s
RangeVar 10.208178244s
$ go build floata.go && ./floata
FuncVar 10.123357283s
RangeVar 10.173007394s
$ go build floata.go && ./floata
FuncVar 9.935580721s
RangeVar 10.109644784s
$ go build floata.go && ./floata
FuncVar 10.070552761s
RangeVar 10.317730473s
$ go build floata.go && ./floata
FuncVar 10.075578601s
RangeVar 10.012273678s
$
$go test-v-run=-长凳=。
测试:警告:没有要运行的测试
通过
BenchmarkFuncVar 100000 12260 ns/op 8192 B/op 1 allocs/op
基准范围VAR 100000 12125 ns/op 8192 B/op 1 allocs/op
ok so/测试2.703s
$go test-v-run=-长凳=。
测试:警告:没有要运行的测试
通过
BenchmarkFuncVar 100000 12620 ns/op 8192 B/op 1 allocs/op
BenchmarkRangeVar 100000 12623 ns/op 8192 B/op 1 allocs/op
正常so/测试2.782s
$go test-v-run=-长凳=。
测试:警告:没有要运行的测试
通过
BenchmarkFuncVar 100000 12730 ns/op 8192 B/op 1 allocs/op
基准范围100000 12971 ns/op 8192 B/op 1 allocs/op
正常so/测试2.852s
$
应已删除评论的要求。这里有一个仅使用系统时间的基准测试
package main
import (
"fmt"
"time"
)
const N = 1e6
var f32 = make([]float32, 1024)
var slice64 []float64
func FuncVar(f32 []float32) []float64 {
f64 := make([]float64, len(f32))
var f float32
var i int
for i, f = range f32 {
f64[i] = float64(f)
}
return f64
}
func BenchmarkFuncVar() {
t1 := time.Now()
for i := 0; i < N; i++ {
slice64 = FuncVar(f32)
}
t2 := time.Now()
fmt.Println("FuncVar", t2.Sub(t1))
}
func RangeVar(f32 []float32) []float64 {
f64 := make([]float64, len(f32))
for i, f := range f32 {
f64[i] = float64(f)
}
return f64
}
func BenchmarkRangeVar() {
t1 := time.Now()
for i := 0; i < N; i++ {
slice64 = RangeVar(f32)
}
t2 := time.Now()
fmt.Println("RangeVar", t2.Sub(t1))
}
func main() {
BenchmarkFuncVar()
BenchmarkRangeVar()
}
主程序包
进口(
“fmt”
“时间”
)
常数N=1e6
var f32=make([]float321024)
var slice64[]float64
func FuncVar(f32[]float32][]float64{
f64:=make([]浮点64,len(f32))
变量f浮动32
变量i int
对于i,f=范围f32{
f64[i]=64(f)
}
返回f64
}
func BenchmarkFuncVar(){
t1:=时间。现在()
对于i:=0;i
输出:
$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar 100000 12260 ns/op 8192 B/op 1 allocs/op
BenchmarkRangeVar 100000 12125 ns/op 8192 B/op 1 allocs/op
ok so/test 2.703s
$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar 100000 12620 ns/op 8192 B/op 1 allocs/op
BenchmarkRangeVar 100000 12623 ns/op 8192 B/op 1 allocs/op
ok so/test 2.782s
$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar 100000 12730 ns/op 8192 B/op 1 allocs/op
BenchmarkRangeVar 100000 12971 ns/op 8192 B/op 1 allocs/op
ok so/test 2.852s
$
$ go build floata.go && ./floata
FuncVar 10.479653966s
RangeVar 10.208178244s
$ go build floata.go && ./floata
FuncVar 10.123357283s
RangeVar 10.173007394s
$ go build floata.go && ./floata
FuncVar 9.935580721s
RangeVar 10.109644784s
$ go build floata.go && ./floata
FuncVar 10.070552761s
RangeVar 10.317730473s
$ go build floata.go && ./floata
FuncVar 10.075578601s
RangeVar 10.012273678s
$
$go build floata.go&&./floata
FuncVar 10.479653966s
范围10.208178244s
$go build floata.go&&./floata
FuncVar 10.123357283s
范围变量10.173007394s
$go build floata.go&&./floata
FuncVar 9.935580721s
范围变量10.109644784s
$go build floata.go&&./floata
FuncVar 10.070552761s
范围10.317730473s
$go build floata.go&&./floata
FuncVar 10.075578601s
范围10.012273678s
$
不即使这是一个内置的,它也只能像4行代码那样迭代元素,这真的非常有用。非常感谢您分享您的专业知识。过去几天我一直在玩弄它,但它确实看起来很好,而且很容易掌握。@Alasdair:您关于“:=范围内循环”的低效声明对堆栈或寄存器变量没有意义。我通过基准测试发现了这一点,并在golang-devs上报告了它。嗨,peterSo,我在几周前的基准测试中发现了:=范围问题,并在golang-devs上报告了它。现在重做这个基准,我可以看到,这两者之间没有区别。早期的基准测试很可能存在缺陷。谢谢你仔细检查。