Roh*_*nil 7 encoding json deep-copy go gob
我在用go 1.9.而且我想将对象的深度复制到另一个对象中.我尝试使用encoding/gob和encoding/json来完成它.但是gob编码需要比json编码更多的时间.我看到一些像这样的其他问题,他们建议gob编码应该更快.但我看到完全相反的行为.有人能告诉我,如果我做错了吗?或者比这两个更好更快的深度复制方法?我的对象的结构是复杂和嵌套的.
测试代码:
package main
import (
"bytes"
"encoding/gob"
"encoding/json"
"log"
"time"
"strconv"
)
// Test ...
type Test struct {
Prop1 int
Prop2 string
}
// Clone deep-copies a to b
func Clone(a, b interface{}) {
buff := new(bytes.Buffer)
enc := gob.NewEncoder(buff)
dec := gob.NewDecoder(buff)
enc.Encode(a)
dec.Decode(b)
}
// DeepCopy deepcopies a to b using json marshaling
func DeepCopy(a, b interface{}) {
byt, _ := json.Marshal(a)
json.Unmarshal(byt, b)
}
func main() {
i := 0
tClone := time.Duration(0)
tCopy := time.Duration(0)
end := 3000
for {
if i == end {
break
}
r := Test{Prop1: i, Prop2: strconv.Itoa(i)}
var rNew Test
t0 := time.Now()
Clone(r, &rNew)
t2 := time.Now().Sub(t0)
tClone += t2
r2 := Test{Prop1: i, Prop2: strconv.Itoa(i)}
var rNew2 Test
t0 = time.Now()
DeepCopy(&r2, &rNew2)
t2 = time.Now().Sub(t0)
tCopy += t2
i++
}
log.Printf("Total items %+v, Clone avg. %+v, DeepCopy avg. %+v, Total Difference %+v\n", i, tClone/3000, tCopy/3000, (tClone - tCopy))
}
Run Code Online (Sandbox Code Playgroud)
我得到以下输出:
Total items 3000, Clone avg. 30.883µs, DeepCopy avg. 6.747µs, Total Difference 72.409084ms
Run Code Online (Sandbox Code Playgroud)
icz*_*cza 13
gob差异该encoding/gob包需要传输类型定义:
该实现为流中的每种数据类型编译自定义编解码器,并且当使用单个编码器传输值流时,最有效,分摊编译成本.
当您"首先"序列化类型的值时,还必须包含/传输该类型的定义,因此解码器可以正确地解释和解码流:
gobs流是自我描述的.流中的每个数据项前面都有一个类型的规范,用一小组预定义类型表示.
这里详细解释了这一点:高效Go结构化到磁盘的序列化
因此,在您的情况下,每次都需要创建一个新的gob编码器和解码器,它仍然是"瓶颈",这使得它变慢.从JSON格式编码/解码,类型描述不包括在表示中.
为了证明这一点,做出这个简单的改变:
type Test struct {
Prop1 [1000]int
Prop2 [1000]string
}
Run Code Online (Sandbox Code Playgroud)
我们在这里做的是使字段数组的类型,将值"乘以"一千次,而类型信息实际上保持相同(数组中的所有元素具有相同的类型).像这样创建它们的值:
r := Test{Prop1: [1000]int{}, Prop2: [1000]string{}}
Run Code Online (Sandbox Code Playgroud)
现在运行您的测试程序,我的机器上的输出:
原版的:
2017/10/17 14:55:53总项目3000,克隆平均 33.63μs,DeepCopy avg.2.326μs,总差93.910918ms
修改版:
2017/10/17 14:56:38总项目3000,克隆平均 119.899μs,DeepCopy avg.462.608μs,总差异-1.02812648s
正如您所看到的,在原始版本中JSON更快,但在修改后的版本gob变得更快,因为传输类型信息的成本摊销.
现在开始你的测试方法.这种测量性能的方法很糟糕,并且可能产生非常不准确的结果.相反,你应该使用Go的内置测试和基准测试工具.有关详细信息,请阅读代码和性能的顺序.
这些方法使用反射,因此只能"克隆"可通过反射访问的字段,即:导出.他们通常也不管理指针相等.我的意思是,如果你在一个结构中有2个指针字段,它们都指向同一个对象(指针相等),在编组和解组后,你将得到2个指向2个不同值的不同指针.这甚至可能在某些情况下引起问题.
考虑到上面提到的警告,通常正确的克隆方式需要来自"内部"的帮助.也就是说,克隆特定类型通常只有在该类型(或该类型的包)提供此功能时才可能.
是的,提供"手动"克隆功能并不方便,但另一方面,它将胜过上述方法(甚至可能达到数量级),并且需要克隆过程所需的"工作"内存量最少.
| 归档时间: |
|
| 查看次数: |
11637 次 |
| 最近记录: |