Please consider these two snippets in GO and C++11. In C++ std::vector
is a doubling-array which has amortized O(1) insert operation. How to achieve the same performance in GO? Problem is that this GO code is about 3 times slower on my hardware. Run many times.
Compiled:
go build vec.go
(go version go1.2.1 linux/amd64) g++ -O2 -std=gnu++11 -o vec vec.cc
(g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2) GO version (vec.go):
package main
type X struct {
x int32
y float64
}
const N int = 80000000
func main() {
x := X{123, 2.64}
s := make([]X, 1)
for i := 0; i < N; i++ {
s = append(s, x)
}
}
C++11 version (vec.cc):
#include <vector>
const int N = 80000000;
struct X {
int x;
double y;
};
int main(void)
{
X x{123, 2.64};
std::vector<X> s(1);
for (int i = 0; i < N; ++i) {
s.push_back(x);
}
}
Go's specification doesn't require any particular complexity for append()
, but in practice it's also implemented in ammortized constant time, as described in the answer to this question .
The current implementation works as follows: for array sizes below 1024, it doubles as needed, and above 1024 it increases to 1.25x the original size. Increasing by 1.25x is still amortized constant time, but it has the effect of imposing a higher amortized constant factor than an implementation that always doubles. However 1.25x wastes less memory overall.
If you're getting different performance behavior by only a few times (even at very large N), then you're seeing different constant factors in play. I've noted myself that the machine code produced by the gc
compiler is much more efficient than that generated by gccgo
.
To verify for yourself that Go is operating in ammortized constant time, try plotting the time it takes to run your algorithm for several different values of N.
I've already answered your computational complexity question: append complexity . It is amortized constant time.
My results from your benchmark.
$ rm vec
$ cat vec.cc
#include <vector>
const int N = 80000000;
struct X {
int x;
double y;
};
int main(void)
{
X x{123, 2.64};
std::vector<X> s(1);
for (int i = 0; i < N; ++i) {
s.push_back(x);
}
}
$ g++ -O2 -std=gnu++11 -o vec vec.cc
$ time ./vec
real 0m1.360s
user 0m0.536s
sys 0m0.816s
$ rm vec
$ cat vec.go
package main
type X struct {
x int32
y float64
}
const N int = 80000000
func main() {
x := X{123, 2.64}
s := make([]X, 1)
for i := 0; i < N; i++ {
s = append(s, x)
}
}
$ go version
go version devel +6b696a34e0af Sun Aug 03 15:14:59 2014 -0700 linux/amd64
$ go build vec.go
$ time ./vec
real 0m2.590s
user 0m1.192s
sys 0m1.388s
$
If you know the number of elements before hand, you can preallocate it with:
s := make([]X, 0, N)
for i := 0; i < N; i++ {
s = append(s, x)
}
Also use Go 1.3, the compiler got some optimizations.
And for better vectorization, try gccgo
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.