'. '

Go

From APIDesign

(Difference between revisions)
Jump to: navigation, search
Line 12: Line 12:
=== Forget [[Go]]! ===
=== Forget [[Go]]! ===
-
The above is probably all you need to know about [[Go]]. Because the goal of this post isn't to promote [[Go]]. The post was written to explain that you don't need [[Go]] at all. There are better, faster, more approachable, more toolable alternative [[language]]s. If you are a happy [[Go]] user, stick to it, but if you are considering to use [[Go]] for development of a new system, then the main take away should be: ''Forget Go!'', there is a better way.
+
[[Go]] is mostly used in places where fast start, low system requirements and multi-threaded communication is needed and where lower level language like [[C]] is considered too dangerous. [[Go]] comes with a promise of a system language, yet adding memory safety and automatic [[wikipedia:garbage collection (computer science)|garbage collection]]. If you have such needs and you are looking for a language, you may think that [[Go]] is the right choice. Maybe it is for you, however, it is not the only choice. Let's consider an alternative. Let's consider [[Java]]!
 +
 
 +
==== [[Java]] as a [[Language]] ====
 +
 
 +
[[Java]]!? That slow, interpreted [[language]] which eats enormous amount of memory to execute its [[JVM|virtual machine]] and feels like an [[OS|operating system]] on its own? That [[Java]] which every real [[OS]] level hacker hates? Well, not exactly that one, but first let's enumerate what kind of [[language]] [[Java]] is:
 +
 
 +
* [[wikipedia:static typing|statically typed]]
 +
* [[wikipedia:compiled language|compiled]] language
 +
** into a [[bytecode]]
 +
** or with [[NativeImage]] into native code in the tradition of [[C]]
 +
* with [[wikipedia:memory safety|memory safety]]
 +
* and [[wikipedia:garbage collection (computer science)|garbage collection]]
 +
* and [[OOP|object oriented typing]]
 +
* with [[Monitor|multi-threading concepts]] built into the [[language]] since day one
 +
 
 +
Does that sound familiar? Yes, the [[Java]] language has the same benefits as attributed to [[Go]] language. Moreover those more than twenty years of industry competition for the best [[Java]] [[IDE]] and framework shows: Refactorings, completions, support for various libraries and frameworks make [[Java]] ecosystem way richer than the incubating one [[Go]] offers.
 +
 
 +
==== [[NativeImage]] Gives [[Java]] Effective Runtime ====
 +
 
 +
The classical [[Java]] interpreter and [[JIT]] compiler comes with enormous overhead not suitable for the use-cases targeted by [[Go]]. However, there is a solution. Let's introduce [[GraalVM]] and its [[NativeImage]]!
 +
 
 +
[[NativeImage]] is an ahead of time compiler of [[Java]] and other [[JVM]] [[language]]s. [[NativeImage]] gives [[Java]] the runtime behavior [[Go]] provides. In particular [[NativeImage]] gives [[Java]] (and any other [[JVM]] language) following:
 +
 
 +
* instant startup
 +
* no interpreter/dynamic compilation overhead
 +
* low memory consumption
 +
 
 +
If you have a pre-occupations against [[Java]] (based on the knowledge of the [[JIT]] version) forget them. We'll use the best of [[Java]] (or any other [[JVM]] language like [[Kotlin]]) and combine them with [[NativeImage]] to form an ecosystem which addresses the same issues as [[Go]] attempts and does it surprisingly well!
 +
 
-
Let's start by enumerating what are the problems with the [[Go]] language.
 
==== Slow ====
==== Slow ====
Line 64: Line 91:
=== [[Go]], [[Java]] [[go]]! ===
=== [[Go]], [[Java]] [[go]]! ===
-
[[Java]]!? That slow, interpreted [[language]] which eats enormous amount of memory to execute its [[JVM|virtual machine]] and feels like an [[OS|operating system]] on its own? That [[Java]] which every real [[OS]] level hacker hates? Yes, that one. Well, not exactly that [[Java]], but rather a [[NativeImage]] - an ahead of time compiler. Let's enumerate what [[Java]] is:
 
-
 
-
* [[wikipedia:static typing|statically typed]]
 
-
* [[wikipedia:compiled language|compiled]] language
 
-
** into a [[bytecode]]
 
-
** or with [[NativeImage]] in the tradition of [[C]]
 
-
* with [[wikipedia:memory safety|memory safety]]
 
-
* and [[wikipedia:garbage collection (computer science)|garbage collection]]
 
-
* and [[OOP|object oriented typing]]
 
-
* with [[Monitor|multi-threading concepts]] built into the [[language]] since day one
 
-
 
-
Does that sound familiar? Yes, the [[Java]] language has the same benefits as attributed to [[Go]]. Moreover (in combination with [[NativeImage]]) one also gets similar runtime behavior. [[NativeImage]] gives [[Java]] (and any other [[JVM]] language) following:
 
-
 
-
* instant startup
 
-
* no interpreter/dynamic compilation overhead
 
-
* low memory consumption
 
-
 
-
If you have a pre-occupations against [[Java]] forget them. We'll use the best of [[Java]] (or any other [[JVM]] language like [[Kotlin]]) and combine them with [[NativeImage]] to form an ecosystem which is clearly better than anything [[Go]] can provide.
 
==== [[Java]] is Fast ====
==== [[Java]] is Fast ====

Revision as of 09:48, 1 October 2018

Go is a programming language developed by Google. When it was introduced in 2009, it was promoted as:

After the usual initial hype it managed to keep some of its coolness. Primarily because of the rise of docker (as most of the docker ecosystem is written in Go).

Contents

Forget Go!

Go is mostly used in places where fast start, low system requirements and multi-threaded communication is needed and where lower level language like C is considered too dangerous. Go comes with a promise of a system language, yet adding memory safety and automatic garbage collection. If you have such needs and you are looking for a language, you may think that Go is the right choice. Maybe it is for you, however, it is not the only choice. Let's consider an alternative. Let's consider Java!

Java as a Language

Java!? That slow, interpreted language which eats enormous amount of memory to execute its virtual machine and feels like an operating system on its own? That Java which every real OS level hacker hates? Well, not exactly that one, but first let's enumerate what kind of language Java is:

Does that sound familiar? Yes, the Java language has the same benefits as attributed to Go language. Moreover those more than twenty years of industry competition for the best Java IDE and framework shows: Refactorings, completions, support for various libraries and frameworks make Java ecosystem way richer than the incubating one Go offers.

NativeImage Gives Java Effective Runtime

The classical Java interpreter and JIT compiler comes with enormous overhead not suitable for the use-cases targeted by Go. However, there is a solution. Let's introduce GraalVM and its NativeImage!

NativeImage is an ahead of time compiler of Java and other JVM languages. NativeImage gives Java the runtime behavior Go provides. In particular NativeImage gives Java (and any other JVM language) following:

  • instant startup
  • no interpreter/dynamic compilation overhead
  • low memory consumption

If you have a pre-occupations against Java (based on the knowledge of the JIT version) forget them. We'll use the best of Java (or any other JVM language like Kotlin) and combine them with NativeImage to form an ecosystem which addresses the same issues as Go attempts and does it surprisingly well!


Slow

Go is slow. The same algorithm written in Go runs at least twice as slow than the same algorithm written in Java or C. I maintain a project to measure Turing Speed of various programming languages on a variant of Ancient and well known Sieve of Eratosthenes algorithm. What follows are results of https://github.com/jtulach/sieve revision a671eb115 compiled with go1.9.2 on Ubuntu 16.04:

sieve/go$ ./go | grep Hundred
Hundred thousand prime numbers in 253 ms
Hundred thousand prime numbers in 263 ms
Hundred thousand prime numbers in 261 ms
Hundred thousand prime numbers in 270 ms
Hundred thousand prime numbers in 250 ms
Hundred thousand prime numbers in 277 ms
Hundred thousand prime numbers in 241 ms

now change the directory to C version and try the same:

sieve/c$ sieve | grep Hundred
Hundred thousand prime numbers in 100 ms
Hundred thousand prime numbers in 101 ms
Hundred thousand prime numbers in 98 ms
Hundred thousand prime numbers in 102 ms
Hundred thousand prime numbers in 101 ms
Hundred thousand prime numbers in 108 ms
Hundred thousand prime numbers in 97 ms

Can anybody explain to me what is so interesting on a language 2.5x times slower than C!? Maybe it is the language safety? But then read on: you don't have to give so much speed up and you can still feel at least the same level of safety!

Hard for Coding

One of the original Go mottos was to not require integrated development environments. Obviously one can code with vi or sed, but at cost of complete loss of productivity. Thus I doubt the IDE-less vision materialized. Definitely not more than for C.

Coding, editing, compiling, fixing errors, debugging when writing Go code feels to me like editing Java twenty years ago (at that time I was writing the 1st IDE for Java - Xelfi which later became NetBeans - obviously there was no IDE for Java at that time). Do your edits in notepad or etc., go to command line, compile, read the errors, locate them in the editor, try to fix them (without any hint about the Go APIs), repeat until the Go compiler is happy and you get your executable. Run to get a failure. Try to seek for a debugger. No, it is not gdb, search more. Give up, and resort to printf logging. Honestly, it is a disaster to usability for everyone spoiled by enormous competition between IDEs for Java in the last twenty years. But maybe the whole story shouldn't be that dark. Maybe there are people productive with Go - especially if you want to hire the few most expensive experts that code Go for living...

However from perspective of a regular StackOverFlow developer, the tooling is really bad. There is an IDE that supports Go, but even its basic editing features aren't for free. There is an implementation of LSP server, but your mileage may vary. Looks like Go is years behind any language adopted by the industry.

Isolated

Go is isolated. The whole stack is written from scratch and not based only anything the industry shares. It is not based on LLVM stack. It is not build around GCC infrastructure. It is written by Google from top to bottom.

This has a negative effect on features, as well as speed. The team paid for Go support isn't infinite, and thus it cannot address all the incoming requests immediately. Yet it needs to reinvent everything (including a wheel) again due to uniqueness of the overall Go language/compiler implementation. As a result Go falls behind in many respects compared to languages well adopted by the industry.

This is not to say everything in bad in Go. If you are working in an ecosystem that is build with Go (e.g. you are coding against Docker APIs or you are a Google employee), it may still be beneficial to use Go. But otherwise, let's consider Java!

Go, Java go!

Java is Fast

Running the same Sieve of Eratosthenes algorithm with standard Java 1.8 gives you:

sieve$ mvn -f java/algorithm/ package exec:java | grep Hundred
Hundred thousand primes computed in 100 ms
Hundred thousand primes computed in 108 ms
Hundred thousand primes computed in 93 ms
Hundred thousand primes computed in 90 ms
Hundred thousand primes computed in 84 ms
Hundred thousand primes computed in 87 ms
Hundred thousand primes computed in 85 ms
Hundred thousand primes computed in 84 ms
Hundred thousand primes computed in 84 ms
Hundred thousand primes computed in 84 ms
Hundred thousand primes computed in 86 ms

with NativeImage it is slightly slower, but still faster than Go:

sieve$ mvn -f java/algorithm/ -Dnative.image=/graalvm/bin/native-image package
sieve$ java/algorithm/target/sieve | grep Hundred
Hundred thousand primes computed in 184 ms
Hundred thousand primes computed in 143 ms
Hundred thousand primes computed in 196 ms
Hundred thousand primes computed in 222 ms
Hundred thousand primes computed in 182 ms
Hundred thousand primes computed in 158 ms
Hundred thousand primes computed in 150 ms
Hundred thousand primes computed in 176 ms
Hundred thousand primes computed in 138 ms
Hundred thousand primes computed in 140 ms
Hundred thousand primes computed in 146 ms
Hundred thousand primes computed in 170 ms
Hundred thousand primes computed in 156 ms

NativeImage Gives You single Binary

Just like Go compiler, also NativeImage gives you a single binary which can be used and deployed to your docker or any other restricted system:

sieve$ mvn -f java/algorithm/ -Dnative.image=/graalvm/bin/native-image package
sieve$ ls -lh java/algorithm/target/sieve
4,8M java/algorithm/target/sieve

That single 4.8MB file is all you need. That is a comparable size to Go result which gives you file roughly of 2MB size. Certainly way smaller than trying to pack the standard HotSpot JDK.

Java Requires Little of Memory

TBD: Needs some explanation or tuning:

PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                                               
20   0  277680 267388   4204 R 100,0  1,7   0:12.78 sieve.java 
20   0    9016   6356   1132 S 100,7  0,0   0:14.22 sieve.go

The Tooling for Java

Clearly nothing compares to twenty years of industry competition for the best Java IDE. Refactorings, completions, support for various libraries and frameworks. This is not something the magnitude smaller Go ecosystem can compete with. With Java you can easily reuse the existing skills of millions of developers without teaching them new tricks and language from the ground. You can build on shoulders of giants.

Moreover NativeImage isn't restricted to Java. It processes any JVM language. As such you can code in Scala or Kotlin or any other language that compiles to bytecode enlarging the options even more.

Summary

NativeImage makes Java competitive with Go. Not only it benefits from Java ecosystem features, but it even yields faster code, while keeping up on the essential aspects Go was invented for: NativeImage produces single self-contained binary with instant startup and low memory consumption.

Java and NativeImage is a great choice and full replacement of Go.

PS: Next time we look at the interface to C (e.g. operating system API).

Personal tools
buy