Reputation: 9
Go standard lib, Json serialization performance question...JSON is slower than XML and GOB, while json size less than xml file size?
please help point out anything mistake?
docker@dockhost:~/go/projects/wiki$ go run encoding.go
2016/05/24 00:52:16 Serialization by JSON elapsed: 2152195 us
2016/05/24 00:52:16 students.json 19177782
2016/05/24 00:52:17 Serialization by GOB elapsed: 748867 us
2016/05/24 00:52:17 students.gob 9305166
2016/05/24 00:52:18 Serialization by XML elapsed: 1507397 us
2016/05/24 00:52:18 students.xml 26177780
docker@dockhost:~/go/projects/wiki$ go run encoding.go
2016/05/24 00:52:32 Serialization by JSON elapsed: 1388153 us
2016/05/24 00:52:32 students.json 19177782
2016/05/24 00:52:33 Serialization by GOB elapsed: 502814 us
2016/05/24 00:52:33 students.gob 9305166
2016/05/24 00:52:34 Serialization by XML elapsed: 897859 us
2016/05/24 00:52:34 students.xml 26177780
docker@dockhost:~/go/projects/wiki$ go run encoding.go
2016/05/24 00:52:41 Serialization by JSON elapsed: 1290359 us
2016/05/24 00:52:41 students.json 19177782
2016/05/24 00:52:42 Serialization by GOB elapsed: 434203 us
2016/05/24 00:52:42 students.gob 9305166
2016/05/24 00:52:42 Serialization by XML elapsed: 862379 us
2016/05/24 00:52:42 students.xml 26177780
Code:
package main
import (
"log"
"encoding/json"
"encoding/gob"
"encoding/xml"
"math/rand"
"strconv"
"os"
"time"
)
const (
Male=iota
Female
Unknown
ALL=100000
)
type Person struct {
Name string
Id string
Age int
Gender int
}
type Student struct {
Person Person
Grade int
Class string
Teacher Person
}
func (s Student) String() string{
v,err:=json.Marshal(s)
if err!=nil {
log.Fatal("Marshal failed",s)
}
return string(v)
}
var students []Student
func init(){
students=make([]Student,ALL)
for i:=0;i<ALL;i++ {
students[i].Grade=rand.Intn(5)
students[i].Class=strconv.Itoa(students[i].Grade)+",class"+strconv.Itoa(rand.Intn(10))
students[i].Person.Name="Student "+strconv.Itoa(i)
students[i].Person.Id="11001234512345551"+strconv.Itoa(rand.Intn(10))
students[i].Person.Age=10+rand.Intn(10)
students[i].Person.Gender=rand.Intn(3)
students[i].Teacher.Id="22001154365151344"+strconv.Itoa(rand.Intn(10))
students[i].Teacher.Name="Teacher "+strconv.Itoa(i)
students[i].Teacher.Age=40+rand.Intn(10)
students[i].Teacher.Gender=rand.Intn(3)
}
}
func toJsonFile(){
f,err:=os.OpenFile("students.json",os.O_RDWR ,0600)
if err!=nil {
log.Fatal("Can't open students.json "+ err.Error())
}
defer f.Close()
en:=json.NewEncoder(f)
err=en.Encode(students)
if err!=nil {
log.Fatal(err)
}
}
func loadJsonFile(){
f,err:=os.Open("students.json")
if err!=nil {
log.Fatal(err)
}
defer f.Close()
dec:=json.NewDecoder(f)
ss:=make([]Student,ALL)
err=dec.Decode(&ss)
if err!=nil {
log.Fatal(err)
}
// log.Println(ss)
}
func toGobFile(){
f,err:=os.OpenFile("students.gob",os.O_RDWR ,0600)
if err!=nil {
log.Fatal("Can't open students.gob "+ err.Error())
}
defer f.Close()
en:=gob.NewEncoder(f)
err=en.Encode(students)
if err!=nil {
log.Fatal(err)
}
}
func loadGobFile(){
f,err:=os.Open("students.gob")
if err!=nil {
log.Fatal(err)
}
defer f.Close()
dec:=gob.NewDecoder(f)
ss:=make([]Student,ALL)
err=dec.Decode(&ss)
if err!=nil {
log.Fatal(err)
}
// log.Println(ss)
}
func toXmlFile(){
f,err:=os.OpenFile("students.xml",os.O_RDWR ,0600)
if err!=nil {
log.Fatal( err.Error())
}
defer f.Close()
en:=xml.NewEncoder(f)
err=en.Encode(students)
if err!=nil {
log.Fatal(err)
}
}
func loadXmlFile(){
f,err:=os.Open("students.xml")
if err!=nil {
log.Fatal(err)
}
defer f.Close()
dec:=xml.NewDecoder(f)
ss:=make([]Student,ALL)
err=dec.Decode(&ss)
if err!=nil {
log.Fatal(err)
}
// log.Println(ss)
}
func main(){
start:=time.Now()
toJsonFile()
loadJsonFile()
end:=time.Now()
log.Printf("Serialization by JSON elapsed: %d us",end.Sub(start)/1000)
fi,err:=os.Stat("students.json")
if err!=nil {
log.Fatal(err)
}
log.Println(fi.Name(), fi.Size())
start=time.Now()
toGobFile()
loadGobFile()
end=time.Now()
log.Printf("Serialization by GOB elapsed: %d us",end.Sub(start)/1000)
fi,err=os.Stat("students.gob")
if err!=nil {
log.Fatal(err)
}
log.Println(fi.Name(), fi.Size())
start=time.Now()
toXmlFile()
loadXmlFile()
end=time.Now()
log.Printf("Serialization by XML elapsed: %d us",end.Sub(start)/1000)
fi,err=os.Stat("students.xml")
if err!=nil {
log.Fatal(err)
}
log.Println(fi.Name(), fi.Size())
}
Upvotes: 0
Views: 3640
Reputation: 3618
As you report, your benchmark has a lot of inter-run variability. This makes it difficult to reason about the problem. What we really want is a benchmark that always gives the same results, no matter what time of the day we run it.
I revised your benchmark slightly so that it easier to reproduce reliably the results:
1. I serialize the data to memory (as a byte slice[]byte
),
2. I avoid overflowing the processor's cache with data (i.e., use little data).
There is a standard way to write benchmarks in Go, to get more reproducible results (https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go) but in this instance, I have not found it necessary.
See my code at https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/extra/golang/serialization
On my test server (a Skylake processor configured for testing, running at a flat 3.4 GHz, with go 1.7), I get...
2016/12/22 09:55:54 Serialization by JSON elapsed: 599 us
2016/12/22 09:55:54 serialized size in bytes: 18781
2016/12/22 09:55:54 Serialization by GOB elapsed: 230 us
2016/12/22 09:55:54 serialized size in bytes: 9066
2016/12/22 09:55:54 Serialization by XML elapsed: 2404 us
2016/12/22 09:55:54 serialized size in bytes: 25780
As you can see with my results, JSON is just slighly larger (30%) than XML, and GOB is much smaller. This is in agreement with your results. Still in agreement with your results, GOB is much faster than XML and JSON.
However, JSON serialization is much faster than XML serialization (by a factor of 4). GOB is twice as fast as JSON.
You will get different results on your own hardware, but I suspect you will get fairly consistent numbers (little inter-run variability), especially if you disable CPU features such as TurboBoost.
What would happen if we were to actually serialize to disk or use large blobs of data? It would not change the performance ordering since GOB is faster and smaller, JSON is in the middle with respect to both data size and processing size, and XML is more bloated and slower to process.
So I think we can safely conclude that we have the following...
GOB is smaller and faster.
JSON is small and fast.
XML is large and slow.
Upvotes: 1
Reputation: 956
The default json encoder/decoder performs a lot of reflection. Check out https://github.com/pquerna/ffjson for a drop in replacement that generates code for greatly improved performance.
Upvotes: 0