Is Go a Systems Programming Language?
With automatic garbage collection, is Go really suitable as a systems programming language?
A topic that arise from time to time is whether Go is a systems programming language. The creators of Go has characterized it as such but many object to that label.
With automatic garbage collection it does not seem to fit the bill. You would not want to write an operating system kernel e.g. with a language using a garbage collector.
However it helps to clarify by looking at wikipedia definition of systems programming:
Systems programming, or system programming, is the activity of programming computer system software.
The primary distinguishing characteristic of systems programming when compared to application programming is that application programming aims to produce software which provides services to the user directly (e.g. word processor),
whereas systems programming aims to produce software and software platforms which provide services to other software, are performance constrained, or both (e.g. operating systems, computational science applications, game engines, industrial automation, and software as a service applications).
In this regard I think it is indeed fair to label Go a systems programming language. We can also see this reflected in the types of software built using Go:
- Docker — A container technology. Apps
Bcan run on the same OS in different containers. On container can make it look as if
Ais running on Red Hat Linux while the container for
Bmakes it look as if it is running on Ubuntu Linux.
- Kubernetes — Is a system for managing multiple containers across multiple computers.
- InfluxDB — A database system for storing time series data to be analyzed in realtime.
- Traefik — I used for load balancing. Meaning it takes network requests from clients and try to route it to a server which has available capacity.
- CockroachDB — Distributed database.
- Geth — Implementation of an Ethereum crypto currency node. Can parse and verify the blockchain and its smart contracts.
If you look at this stuff you see that this is not typical end user stuff. It is not Photoshop, MS Word or Angry Birds. It is not stuff that normal end users interact with directly. Rather it is services user by end user software.
This is software that often is performance critical. How many requests can be handled, amount of memory used, latency and so on are important metrics. In these circumstances you want programming languages which make it easy to utilize hardware resources in an optimal way. These resources include things such as:
- Microprocessor cores.
Go is designed specifically to give developers fine control over these resources. It has a built in concurrency system based on so called goroutines which is a hybrid between coroutines and hardware threads. This allows workloads to be easily be distributed over multiple CPU cores.
While Go does not allow the same fined tuned control of memory usage as given by C/C++ it gives much stronger control than managed languages such as Java, C#, Python etc. You can define memory layout for object in Go and use real pointers to point to subsets of those objects. This allows you do e.g. create custom memory allocators on top of the garbage collection system or keep allocations to a minimum.
Thus you have better ability than say Java in limiting your use of a limited resources such as memory. You are also able to arrange blocks of memory in a fashion which is more optimal for cache usage.
These are things that matter for systems programming. For application programming it is not as well suited. Take languages such as Objective-C or Swift. They allow you to easily define a GUI and store in a file. Later the file can be loaded and button actions connected to methods in your code.
One thing I often associate with system software is real time systems. In OS kernels, microprocessors, robots etc you need very low latency to respond to the real world. Typically garbage collected languages are poorly suited for this as they often periodically freeze to collect unused memory. Imagine a rocket such as the Falcon 9 throttle its engines while trying to land, and then suddenly a garbage collector kicking in and causing updating of the thrust direction and angle to briefly stop. The rocket would likely crash into the ground.
Here is an interesting difference between Java and Go. Java comes with a variety of garbage collectors which can be tuned and tweaked in all sorts of ways. Usually emphasis is not on low latency but maximum throughput.
While this is still something I try to understand better, the Go team has gone entirely the opposite direction. They have built garbage collector without much you can tweak and which is heavily optimized towards low latency. While a normal Java garbage collector as far as I understand stops execution for about 50 milliseconds on average, a Go garbage collector only does that for 0.5 milliseconds.
Now it could be argue that Java chooses performance instead, but whatever advantages their garbage collector gives, it doesn’t seem to follow in various performance tests:
- Go vs Java benchmarks: this is a collection of some well defined smaller programs used in performance tests.
- Simple performance test by Sunny Radadiya.
I have had interactions with people working for NASA on twitter in the past whom have claimed to use Go for collecting data from measuring instruments. Since measurements happen in real time, you cannot have stop-the-world garbage collection.
Over the years I have kept hearing stories like that about Go, but you seldom hear anything like that about Java or C#. Thus Go does seem to fit into a space between C/C++ and Java/C#. Sunny characterized it this way:
Go lang and Java are not supposed to serve the same type of tasks — Java is enterprise development language whereas Go is a system programming language.