- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在使用 go 1.9
。我想将对象的值深度复制到另一个对象中。我尝试使用 encoding/gob 和 encoding/json 来完成。但是gob编码比json编码要花更多的时间。我看到其他一些问题,例如 this他们建议 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))
}
我得到以下输出:
Total items 3000, Clone avg. 30.883µs, DeepCopy avg. 6.747µs, Total Difference 72.409084ms
最佳答案
gob
区别encoding/gob
包需要传输类型定义:
The implementation compiles a custom codec for each data type in the stream and is most efficient when a single Encoder is used to transmit a stream of values, amortizing the cost of compilation.
当您“首先”序列化一个类型的值时,还必须包含/传输该类型的定义,这样解码器才能正确解释和解码流:
A stream of gobs is self-describing. Each data item in the stream is preceded by a specification of its type, expressed in terms of a small set of predefined types.
这里有详细的解释:Efficient Go serialization of struct to disk
因此,虽然在您的情况下每次都需要创建一个新的 gob 编码器和解码器,但它仍然是“瓶颈”,是导致速度变慢的部分。编码为 JSON 格式/从 JSON 格式解码,类型描述不包含在表示中。
为了证明这一点,做这个简单的改变:
type Test struct {
Prop1 [1000]int
Prop2 [1000]string
}
我们在这里所做的是将字段类型设为数组,将值“乘以”一千次,而类型信息实际上保持不变(数组中的所有元素都具有相同的类型)。像这样创造它们的值(value):
r := Test{Prop1: [1000]int{}, Prop2: [1000]string{}}
现在运行你的测试程序,在我的机器上输出:
原文:
2017/10/17 14:55:53 Total items 3000, Clone avg. 33.63µs, DeepCopy avg. 2.326µs, Total Difference 93.910918ms
修改版本:
2017/10/17 14:56:38 Total items 3000, Clone avg. 119.899µs, DeepCopy avg. 462.608µs, Total Difference -1.02812648s
如您所见,在原始版本中 JSON 速度更快,但在修改后的版本中 gob
变得更快,因为传输类型信息的成本被分摊了。
现在开始您的测试方法。这种衡量性能的方法很糟糕,会产生非常不准确的结果。相反,您应该使用 Go 的内置测试和基准测试工具。详情请阅读Order of the code and performance .
这些方法与反射一起工作,因此只能“克隆”可通过反射访问的字段,即:导出。此外,他们通常不管理指针相等性。我的意思是,如果你在一个结构中有 2 个指针字段,都指向同一个对象(指针相等),在编码和解码之后,你将得到 2 个不同的指针指向 2 个不同的值。在某些情况下,这甚至可能会导致问题。它们也不处理自引用结构,这充其量会返回一个错误,或者在错误的情况下导致无限循环或 goroutine 堆栈超出。
考虑到上述注意事项,正确的克隆方法通常需要来自“内部”的帮助。也就是说,克隆特定类型通常只有在该类型(或该类型的包)提供此功能时才有可能。
是的,提供“手动”克隆功能并不方便,但另一方面,它将优于上述方法(甚至可能好几个数量级),并且需要最少的“工作”内存克隆过程。
关于json - 在 golang、JSON 与 gob 中深度复制对象的更快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46790190/
我正在使用“RPUSH”命令将我的对象推送到我的 redis 库中。 // object is of type interface var network bytes.Buffer gob.NewEn
这个问题在这里已经有了答案: Unable to decode gob data (1 个回答) 关闭 4 年前。 这是我的 Playground ,我正在尝试序列化结构列表并从文件中读回。 htt
在我的 Go 程序中,我用 gob 编码 []byte 数据 buf := new(bytes.Buffer) enc := gob.NewEncoder(buf) //dat
我想开发一个 type data struct 来实现磁盘存储。我在将数据对象编码为字节时遇到了问题。对于编码,我想使用 encoding/gob 包。 package data import (
我正在尝试将结构保存到 gob,但文件缺少嵌套类型的值。我可以自己保存 Matrix 类型,但 Network 结构的 gob 数据不包括 Matrix 值。有没有办法将这个嵌套结构保存到 gob 中
我在我的代码中做这样的事情 test1 = make(map[string]interface{}) test2 = make(map[string]interface{}) test3 = make
我有一个正在编码的简单结构类型。但是,我在解码数据时犯了根本性的错误。每次我尝试对其进行解码时,都会出现 EOF panic 错误。 //将 map 编码为gob。将 gob 保存到磁盘。从磁盘读取
我最近重组了我的代码,现在 main 包下有两个包:chain 和 api。 在 chain 中,我定义了一些结构 SomeStruct1、SomeStruct2 和这些结构的接口(interface
我正在尝试实现一个基于接口(interface)的消息队列,其中将作业作为字节推送到 Redis 队列。但是我在尝试解码字节流时不断收到 EOF 错误。 https://play.golang.org
我正在尝试将 []byte 通过 chan 提供给 gob 解码器。它可以工作,但起初解码器会抛出一大堆 EOF 错误,然后停止。当它停止抛出错误时,程序的行为与我预期的完全一样,它解码 gob 并正
我有一个非常非常大的 map 阵列(不是 slice ),然后我试图对其进行编码。我真的需要避免复制数组,但我不知道该怎么做。 到目前为止,我有这个: func doSomething() { va
我正在尝试将 gob 编码的数据保存在磁盘上的一个文件中,作为一个简单的数据存储。但是,当我下次打开它时,gob 编码器会忽略文件中已有的任何数据,并在发送数据之前重新发送已发送格式的定义。看到 go
我遇到了 gob 协议(protocol)问题(或者可能是一般的网络问题,我的知识薄弱),我不明白为什么下面的代码不能正常工作。它只是一个维护开放 TCP 连接并通过它发送多个 gob 的简单示例。该
这似乎无法正常工作,我不确定自己做错了什么。我正在尝试将 map 转换为 gob,对二进制文件进行 gzip 压缩并将其保存到文件中,然后再读回。 type Object struct { mystr
我们能否期望两个 Go 对象 x, y 使得 x 等于 y(假设接口(interface)和映射没有技巧,只是结构和数组)gob_encode(x) 和 gob_encode(y) 的输出将始终是一样
我已经阅读了 ( gob) 的文档,但我遇到了一些问题: 现在我知道如何像这样编码结构和解码了: func main() { s1 := &S{ Field1: "Hello
当我尝试使用 gob 编码器将类型为 map[mapKey]string 的 map 保存到文件中时,它没有将字符串保存到文件中。 这里的mapKey是struct,map value是长json字符
我主要使用 Python,但也在玩 Go。我写了下面的代码来做一些在 python 中非常简单的事情,我希望它也可以在 Go 中完成。 package main import ( "bytes
我有一个包含未导出字段的结构,应该进行 gob 编码和解码。 说: type A struct { s int } func (a *A) Inc() { a.s++ } 显然,在这种
是否可以使用 Gob 编码将结构串联附加到同一文件中?它适用于写作,但是当我不止一次地使用解码器阅读时,我遇到了: extra data in buffer 所以我首先想知道这是否可行,或者我是否应该
我是一名优秀的程序员,十分优秀!