I like shiny new things. Zig is very new, and very shiny, and very fast. I have no experience writing non-garbage collected languages, so I want to test it out and compare Zig with GoLang.
Benchmark
The benchmark is a HTTP API wrapper around SQLite: `
/write- takes a
- JSON
- {
- “name”
} and write is to the DB
/read
returns
100
items
`
The SQL: `
– TABLE
CREATE
TABLE IF NOT
EXISTS test (id INTEGER
PRIMARY KEY AUTOINCREMENT, name REAL , timestamp
INTEGER );
– READ
SELECT id, name, timestamp
FROM test ORDER
BY id DESC LIMIT 100 ;
– WRITE
INSERT
INTO test(name, timestamp ) VALUES (?, ?);
– SETTINGS
PRAGMA journal_mode WAL; – To increase write concurrency
PRAGMA busy_timeout 5000 ; – To wait on busy requests
`
The tests on my MacBook Pro: ` ab -c 100 -n 100000 -p postdata.json http: //
127.0 . 0 . 1 : 3000 / write
ab -c 100 -n 100000 http: //
127.0 . 0 . 1 : 3000 / read
`
Zig
I am using the Zap HTTP framework and zig-sqlite wrapper.
First I did the stupid things:
- like not allocate enough characters for the return message, so it silently did nothing.
- Didn’t use the right version of Zig, everything is changing quickly.
- Didn’t understand the
ArenaAllocatorso I had a memory leak.
Also, I used a single instance sqlite.DB across the threads spawned by Zap. This caused everything to blow up under load, reporting arcane error messages. To fix this I used the threadlocal keyword:
threadlocal var mainDB: ?sqlite.Db = null ;
I couldn’t find a hook in Zap to call when a thread is spawned, so on the first request to a thread it checks if it is null, connects to the DB and builds all the prepared statements. So there server does require some warming up.
With zig build -Doptimize=ReleaseSafe run we get the results:
- Write: 16,770 rps, 67% CPU, 12 MB Memory
- Read: 21,398 rps, 500% CPU, 12 MB Memory, 8 Errors
The errors seem to be from requests not correctly disconnecting, these errors occasionally killed ab which is weird.
Golang
I have written too many Golang services, so I couldn’t be bothered with this one and told ChatGPT to write it. With some small edits, that frankly ChatGPT should be embarrassed about, I had a working service. If you have seen a Go service before you know what this looks like.
- Write: 16,239 rps, 180% CPU, 65 MB Memory
- Read: 15,470 rps, 670% CPU, 71 MB Memory
Reactions
Con #1: Zig is New
- Zig is changing fast and some dependencies target master and some the stable 13.0. This means you pretty much have to run master.
- Since tools like ChatGPT train on dated content, Zig suggestions or code generation is old or non-existent.
- Other tools like VSCode have gaps in their tooling, like linking to source from dependencies
Pro #1: Zig in Fast
- Zig is significatly faster than Go for
/readendpoint. Zig also uses much less RAM and much less CPU. /writeendpoint is probably HDD bound, and the reason for similar results.- The Go binary is 7.6 MB large and Zig is 2.2 MB.
Con #2: Zig is Low Level
- The LOC for the Zig was 150-ish lines and Go was 100. Each line of Zig was very dense, and their were little landmines everywhere. Go was pretty plain, very difficult to fuck it up.
- A web service was probably not the best comparison between the languages, but it was what I am working on.
- Zig error codes are hard to run down. For a bunch of time I was getting weird errors caused by threads. Although I was able to solve them, it took a long time.
- Zig is erroring on read, but only when there are LOTS of requests. I never ran down the problem, not sure if I am just holding it wrong. That isn’t the point though, Go just works and Zig has these little issues. Fixing bugs is fun when you are learning, but torture if you want to produce something.
Pro #3: Zig is shiny
- Zig is fun to code. It is the first low level language that I looked at and liked the aesthetics (Rust and C look like work). Picking it up and trying it out was very easy. Last time I tried C, I spent an afternoon stuck in dependency hell.
- New things are fun to learn. Learning a language that is new is like homesteading, where you have to do everything because no body has done it yet.
Conclusions
I don’t think a web service with SQLite is a very fair comparison. Zig would be better for applications that are performance or size bound like embedded. For my upcoming web service projects I will use GoLang, but I am on the lookout for a Zig project to use the language in anger with. .