Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno

Originally published at deepu.tech.

This is a multi-part series where I’ll discuss concurrency in modern programming languages. I will be building and benchmarking a concurrent web server, inspired by the example from the Rust book, in popular languag…


This content originally appeared on DEV Community and was authored by Deepu K Sasidharan

Originally published at deepu.tech.

This is a multi-part series where I'll discuss concurrency in modern programming languages. I will be building and benchmarking a concurrent web server, inspired by the example from the Rust book, in popular languages like Rust, Go, JavaScript (NodeJS), TypeScript (Deno), Kotlin, and Java to compare concurrency and its performance between these languages/platforms. The chapters of this series are as below.

  1. Introduction
  2. Concurrent web server in Rust
  3. Concurrent web server in Golang
  4. Concurrent web server in JavaScript with NodeJS
  5. Concurrent web server in TypeScript with Deno
  6. Concurrent web server in Java with JVM
  7. Comparison and conclusion of benchmarks

What is concurrency

Concurrency is one of the most complex aspects of programming, and depending on your language of choice, the complexity can be anywhere from "that looks confusing" to "what black magic is this".

Concurrency is the ability where multiple tasks can be executed in overlapping time periods, in no specific order without affecting the final outcome. Concurrency is a very broad term and can be achieved by multi-threading, parallelism, and/or asynchronous processing.

concurrency

First, I suggest you read the introduction post to understand this post better.

Benchmarking & comparison

In the previous posts, I built a simple web server in Rust, Go, Node.js, Deno, and Java. I kept it as simple as possible without using external dependencies as much as possible. I also kept the code similar across languages. In this final post, we will compare the performance of all these implementations to see which language offers the best performance for a concurrent web server.

If the language supports both asynchronous and multi-threaded concurrency, we will try both and a combination of both and pick the best performer for the comparison. The complexity of the application will hence depend on language features and language complexity. We will use whatever the language provides to make concurrency performance as good as possible without over-complicating stuff. The web server will just serve one endpoint, and it will add a sleep of two seconds on every tenth request. This will simulate a more realistic load, IMO.

We will use promises, thread pools, and workers if required and if the language supports it. We won't use any unnecessary I/O in the application.

Disclaimer: I'm not claiming this to be an accurate scientific method or the best benchmark for concurrency. I'm pretty sure different use cases will have different results, and real-world web servers will have more complexity that requires communication between concurrent processes affecting performance. I'm just trying to provide some simple base comparisons for a simple use case. Also, my knowledge of some languages is better than others; hence I might miss some optimizations here and there. So please don't shout at me. If you think the code for a particular language can be improved out of the box to enhance concurrency performance, let me know. If you think this benchmark is useless, well, please suggest a better one :)

All the implementations used in this comparison can be found in this GitHub repository.

Benchmarking conditions

These will be some of the conditions I'll be using for the benchmark.

  • The latest stable release versions of language/runtimes available are used, and as of writing, those are:
    • Rust: 1.58.1-Stable
    • Go: 1.17.6
    • Java: OpenJDK 17.0.2
    • Node.js: 17.4.0
    • Deno: 1.18.1
  • We will be using external dependencies only if that is the standard recommended way in the language.
    • latest versions of such dependencies as of writing will be used
  • We are not going to look at improving concurrency performance using any configuration tweaks
  • We will use ApacheBench for the benchmarks with the below settings:
    • Concurrency factor of 100 requests
    • 10000 total requests
    • The benchmark will be done ten times for each language with a warmup round, and the mean values will be used.
    • ApacheBench version on Fedora: httpd-tools-2.4.52-1.fc35.x86_64
    • Command used: ab -c 100 -n 10000 http://localhost:8080/
  • All the benchmarks are run on the same machine running Fedora 35 on an Intel i9-11900H (8 core/16 thread) processor with 64GB memory.

Comparison parameters

I'll be comparing the below aspects related to concurrency as well.

  • Performance, based on benchmark results
  • Community consensus
  • Ease of use and simplicity, especially for complex use cases
  • External libraries and ecosystem for concurrency

Conclusion

Based on the benchmark results, these are my observations.

Benchmark results

The average values for different metrics across ten benchmark runs are as below:

Average values

As you can see, there isn't any significant difference between the languages when it comes to total time taken for 10k requests which means for a real-world use case the language choice isn't going to be a huge factor for concurrency performance. But of course, if you want the best possible performance, then Rust clearly is faster than other languages as it gives you the highest throughput, followed by Java and Golang. JavaScript and TypeScript are behind them, but not by a considerable margin. The Go version using the built-in HTTP server is the slowest of the bunch due to inconsistent performance across runs, probably due to garbage collection (GC) kicking in, causing spikes. Also interesting is to see the difference between the multi-threaded and asynchronous approaches. While for Rust, multi-threaded implementation performs the best by a slight margin, the asynchronous version performs slightly better for Java and JavaScript. But none of the differences is significant enough to justify suggesting one approach over another for this particular case. But in general, I would recommend using the asynchronous approach if available as it's more flexible without some of the limitations you might encounter with threads.

Here are the best results out of all the runs.

Best values

You can find the results used in the GitHub repo

Community concensus

The community consensus when it comes to concurrency performance is quite split. For example, both Rust and Go communities claim to be the best in concurrency performance. From personal experience, I find them relatively close in performance, with Rust having a slight lead over Go. The Node.js ecosystem was built over the promise of asynchronous concurrency performance, and there are testimonials of huge performance improvements when switching to Node.js. Java also boasts of real-world projects serving millions of concurrent requests without any issues; hence it's hard to take a side here.

Another general observation is that Rust was quite consistent in terms of performance across runs while all other languages had some variance, especially when GC kicks in.

Simplicity

While performance is quite similar between different languages and implementations, ease of use and simplicity is a whole different matter. I think it's also important to differentiate between asynchronous and multi-threaded approaches.

Asynchronous: I personally find Node.js and Deno the simplest and easy-to-use platforms for async concurrency. Golang would be my second choice as it's also easy to use and simple without compromising on features or performance. Rust follows it as it is a bit more complex as it has more features and needs getting used to. I would rate Java last as it requires much more boilerplate, and doing asynchronous programming is more complex than in others. I hope project Loom fixes that for Java.

Multi-threaded: For multi-threaded concurrency, I will put Rust first as it's packed with features, and doing multi-threading is easy and worry-free in Rust. I'll put Java second here as it has a mature ecosystem for multi-threading and is not too difficult to use. Go is very easy to use, but you don't have a lot of control over OS threads else I would rate Go higher than Java. Finally, there are multi-threading capabilities in Node.js and Deno, but they are not as flexible as other languages; hence I'll put them last.

Ecosystem

Rust has the best ecosystem for concurrency, in my opinion, followed by Java and Golang, which have matured options. Node.js and Deno, while not as good as others, offers a descent ecosystem as well

If you like this article, please leave a like or a comment.

You can follow me on Twitter and LinkedIn.


This content originally appeared on DEV Community and was authored by Deepu K Sasidharan


Print Share Comment Cite Upload Translate Updates
APA

Deepu K Sasidharan | Sciencx (2022-02-04T10:11:52+00:00) Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno. Retrieved from https://www.scien.cx/2022/02/04/concurrency-in-modern-programming-languages-rust-vs-go-vs-java-vs-node-js-vs-deno/

MLA
" » Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno." Deepu K Sasidharan | Sciencx - Friday February 4, 2022, https://www.scien.cx/2022/02/04/concurrency-in-modern-programming-languages-rust-vs-go-vs-java-vs-node-js-vs-deno/
HARVARD
Deepu K Sasidharan | Sciencx Friday February 4, 2022 » Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno., viewed ,<https://www.scien.cx/2022/02/04/concurrency-in-modern-programming-languages-rust-vs-go-vs-java-vs-node-js-vs-deno/>
VANCOUVER
Deepu K Sasidharan | Sciencx - » Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/02/04/concurrency-in-modern-programming-languages-rust-vs-go-vs-java-vs-node-js-vs-deno/
CHICAGO
" » Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno." Deepu K Sasidharan | Sciencx - Accessed . https://www.scien.cx/2022/02/04/concurrency-in-modern-programming-languages-rust-vs-go-vs-java-vs-node-js-vs-deno/
IEEE
" » Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno." Deepu K Sasidharan | Sciencx [Online]. Available: https://www.scien.cx/2022/02/04/concurrency-in-modern-programming-languages-rust-vs-go-vs-java-vs-node-js-vs-deno/. [Accessed: ]
rf:citation
» Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno | Deepu K Sasidharan | Sciencx | https://www.scien.cx/2022/02/04/concurrency-in-modern-programming-languages-rust-vs-go-vs-java-vs-node-js-vs-deno/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.