How Much Memory for 1,000,000 Threads in 7 Languages | Go, Rust, C#, Elixir, Java, Node, Python

ThePrimeTime
28 May 202326:21

Summary

TLDRThis blog post explores the memory consumption of handling a million concurrent tasks across various programming languages, including Rust, Go, Java, C#, Python, Node.js, and Elixir. The author compares asynchronous and multi-thread programs, noting significant differences in memory usage. Through synthetic benchmarks, the author tests each language's capability to launch and wait for 10 seconds on tasks, observing that Rust with Tokio async runtime and Go's goroutines performed well with low memory footprint. Surprisingly, C# managed to compete with Rust, while Node.js and Elixir consumed more memory. The author suggests that real-world tests involving tasks like websocket connections would provide a more accurate representation of language performance.

Takeaways

  • 🧠 The script discusses a benchmark comparing memory consumption between asynchronous and multi-thread programs in various programming languages such as Rust, Go, Java, C#, Python, Node.js, and Elixir.
  • 🔍 The author highlights a significant difference in memory consumption among different programs, with some consuming over 100 megabytes and others reaching almost three gigabytes.
  • 📈 A synthetic benchmark was created to test the performance of programs handling a large number of network connections, with the number of tasks controlled by a command-line argument.
  • 🤖 Rust was tested with three different programs using traditional threads, async with Tokio, and async with async-std, showing the language's capabilities with different threading models.
  • 🐹 Go routines were used to demonstrate Go's ability to handle concurrency, with the use of a wait group to manage the completion of tasks.
  • 🌟 Java's introduction of virtual threads in JDK 21 was noted as a significant step forward, bringing it closer to the capabilities of Go routines.
  • 🚀 C# was shown to have first-class support for async-await, which is similar to managed environments found in other languages.
  • 🐍 Node.js was pointed out as having a high memory footprint, especially when handling a large number of connections, due to its event-driven, non-blocking I/O model.
  • 🐍 Python demonstrated surprisingly low memory consumption, especially when using asyncio, which was unexpected compared to other managed runtimes.
  • 🔑 The importance of considering factors such as task launch time and communication speeds, in addition to memory consumption, was emphasized for a comprehensive performance evaluation.
  • 🔍 The author suggests that the benchmark should be expanded to include more realistic use cases, such as handling websocket connections or open TCP connections, to better reflect real-world programming challenges.

Q & A

  • What is the main topic of the blog post discussed in the transcript?

    -The main topic of the blog post is a comparison of memory consumption between asynchronous and multi-thread programs across various popular programming languages when handling a large number of concurrent tasks.

  • Why did the author create a synthetic benchmark for the comparison?

    -The author created a synthetic benchmark because the existing computer programs they needed to compare were complex and differed in features, making it difficult to draw meaningful conclusions from a direct comparison.

  • What programming languages were included in the memory consumption comparison?

    -The programming languages included in the comparison were Rust, Go, Java, C#, Python, Node.js, and Elixir.

  • What is the significance of the GitHub repository mentioned in the transcript?

    -The GitHub repository mentioned is where the author has shared the synthetic benchmark programs written in various languages, allowing others to contribute and test the performance of their own languages.

  • What was the author's observation regarding Node.js in terms of memory consumption?

    -The author observed that Node.js has a high memory consumption, especially when handling a large number of connections, with some programs consuming almost three gigabytes of memory.

  • What is the difference between traditional threads and async/green threads as mentioned in the Rust programs?

    -Traditional threads in Rust are actual OS threads, while async/green threads are managed by the runtime and are lighter in terms of system resources, as seen with async implementations using Tokyo and async-std.

  • What is the concept of 'virtual threads' introduced in Java JDK 21?

    -Virtual threads in Java JDK 21 are a feature that provides a similar concept to Go routines, allowing for a large number of lightweight threads that are managed by the JVM, rather than OS threads.

  • What is the author's opinion on the memory consumption of .NET (C#) in the benchmark?

    -The author was surprised that .NET (C#) had the worst memory footprint in the benchmark, especially considering it requires a significant amount of memory even when idle.

  • How did the author find Python's performance in the memory consumption benchmark?

    -The author found Python's performance surprising, as it fared well in terms of memory consumption, using only half the memory of Java or Node.js.

  • What was the author's final observation on the memory consumption of concurrent tasks?

    -The author observed that a high number of concurrent tasks can consume a significant amount of memory, and that runtimes with high initial overhead, like C#, can handle high workloads more effectively.

Outlines

00:00

🔬 Comparative Memory Consumption in Programming Languages

The speaker initiates a discussion on the memory requirements for running one million concurrent tasks, highlighting the significant variance in memory usage observed across different programs. They delve into a comparative analysis of memory consumption between asynchronous and multi-threaded programs in languages like Rust, Go, Java, C#, Python, Node.js, and others. The speaker recounts a previous experience comparing the performance of network connection handling programs, noting a 20x difference in memory consumption. The discussion leads to the idea of creating a synthetic benchmark for a more controlled comparison, and the speaker invites the audience to contribute to an ongoing project on GitHub aimed at building an interpreter and testing language performance comprehensively.

05:01

🚀 Benchmarking Concurrency in Programming Languages

The speaker describes the creation of a benchmark program across various programming languages to launch and manage concurrent tasks. The program waits for 10 seconds per task before exiting, controlled by a command-line argument. They detail the implementation in Rust using traditional threads, async with Tokio, and async-std, as well as Go's use of goroutines and Java's adoption of virtual threads in JDK 21. The speaker also touches on C#'s async-await support and Node.js's event-driven architecture, before moving on to Python's asyncio and Elixir's async capabilities. The test environment and hardware used for these benchmarks are also mentioned, emphasizing the importance of understanding the memory footprint of each language's runtime.

10:03

📊 Memory Footprint Analysis Across Different Runtimes

The speaker presents the initial memory footprint results of the benchmark, noting the differences between compiled languages like Go and Rust, and managed environments or interpreted languages like Node.js, Java, .NET, Python, and Elixir. They express surprise at certain outcomes, such as .NET's high memory consumption despite not increasing significantly with the addition of tasks. The speaker also points out that the memory consumption of native threads in Rust is quite low compared to other runtimes, and that async tasks or virtual threads might offer a lighter alternative. The summary underscores the significant memory differences between compiled and managed runtimes, as well as the surprising performance of certain languages like Python.

15:05

📈 Scaling Up: Memory Consumption at 10K and 100K Tasks

As the number of tasks increases to 10K and then 100K, the speaker observes the memory consumption trends. They note that non-green threads have been excluded from the benchmarks due to system limitations, and that the memory usage of some languages like C# and Java does not change significantly even with the increase in tasks. The speaker hypothesizes that certain runtimes may be reserving memory or have high initial overheads that allow them to handle high workloads more efficiently. They also express skepticism about the accuracy of the results for some languages, suggesting that more complex tasks or interactions might yield different outcomes.

20:07

🏁 Final Benchmark Observations and Recommendations

The speaker concludes the benchmark by discussing the memory consumption at one million tasks, noting the system limitations that prevented some languages from spawning that many threads. They comment on the surprising performance of C#, which showed an increase in memory usage only at this extreme level. The speaker also points out that Go's memory consumption is significantly higher than expected, contradicting the common perception of it being lightweight. They emphasize that while the comparison focused on memory consumption, other factors like task launch time and communication speeds are also crucial. The speaker suggests future benchmarks should include more realistic tasks like handling websocket connections to better simulate real-world usage.

25:08

👏 Appreciation for the Benchmark and Final Thoughts

In the final paragraph, the speaker expresses appreciation for the work done on the benchmark, commending the author, Peter, for his efforts. They highlight the importance of considering the impact of simple programming constructs like for-each loops on performance, using the example of a chat client built with Node.js. The speaker suggests that even minor details in code can significantly affect a program's efficiency, and encourages the audience to think critically about their programming choices. They end with a call to clap for Peter and to acknowledge the value of the insights gained from the benchmark.

Mindmap

Keywords

💡Memory Consumption

Memory consumption refers to the amount of RAM used by a program or process. In the context of the video, it is a critical metric for comparing the efficiency of different programming languages when handling a large number of concurrent tasks. The video discusses how various languages, such as Rust, Go, Java, and Node.js, manage memory differently, with some being more memory-efficient than others. For example, Go is noted for its low memory consumption due to its efficient garbage collector.

💡Concurrent Tasks

Concurrent tasks are multiple tasks that are executed independently but in parallel, allowing for more efficient use of computing resources. The video script delves into the challenge of running one million concurrent tasks and how it impacts memory usage. It compares different programming environments' abilities to handle such a workload, highlighting the significant differences in memory consumption among them.

💡Asynchronous Programming

Asynchronous programming is a model where execution of tasks is not done in a strictly sequential manner, allowing for non-blocking operations and improved performance in I/O-bound tasks. The video discusses asynchronous programming in the context of memory consumption, comparing it with multi-threaded programs across various languages. For instance, Rust's async with Tokio and async-std libraries are highlighted as efficient for handling asynchronous tasks with lower memory overhead.

💡Go Routines

Go routines are lightweight threads of execution in the Go programming language, designed to make concurrent programming easier. The script mentions go routines as the building block for concurrency in Go, noting their efficiency in handling concurrent tasks with minimal memory overhead. However, it also raises questions about their memory consumption compared to Rust threads.

💡Virtual Threads

Virtual threads are a feature in some programming languages that allow for the creation of thousands of threads without the associated overhead of system threads. The video script discusses Java's introduction of virtual threads in JDK 21, which are similar to Go routines, and how they compare to traditional threads in terms of memory usage and performance.

💡Garbage Collection

Garbage collection is the process of automatically freeing memory that is no longer in use by a program. The script touches on the impact of garbage collection on memory consumption, particularly when dealing with a high number of concurrent tasks. It suggests that languages with managed memory environments, like Java and .NET, might have different memory characteristics compared to languages like Rust that do not rely on garbage collection.

💡Benchmarking

Benchmarking is the process of measuring the performance of a system or component under controlled conditions. The video script describes a synthetic benchmark created by the author to compare memory consumption of different programming languages when running a large number of concurrent tasks. The benchmark results are used to evaluate and compare the efficiency of various languages and runtimes.

💡Node.js

Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine, used for server-side applications and network applications. The script mentions Node.js in the context of its memory consumption when handling a large number of connections, noting that it tends to use more memory compared to other languages like Go and Rust.

💡Rust

Rust is a systems programming language known for its focus on performance, safety, and concurrency. The video script frequently refers to Rust as a language that performs well in terms of memory consumption, especially when using its thread and async features. It is highlighted as a language that outperforms others in the benchmark for running a high number of concurrent tasks.

💡C#

C# is a programming language developed by Microsoft as part of its .NET initiative. The script discusses C# in the context of its memory consumption, noting that it has a high initial memory footprint but remains competitive even when scaling up to one million concurrent tasks. It also mentions C#'s support for async-await, which is similar to Rust's async features.

💡Elixir

Elixir is a dynamic, functional language designed for building scalable and maintainable applications, which runs on the Erlang virtual machine (BEAM). The video script mentions Elixir for its async capabilities and its memory consumption when running a large number of tasks, noting that it has a surprisingly high memory usage in the benchmark.

Highlights

Comparison of memory consumption between asynchronous and multi-thread programs across popular languages.

Performance comparison of computer programs handling a large number of network connections.

Memory consumption can vary significantly, with some programs exceeding others by 20x.

Node.js consumes more memory at 10K connections compared to others.

Introduction of synthetic Benchmark to compare performance directly.

Invitation to contribute to the synthetic Benchmark on GitHub.

Building a server for full interpretation and remote compilation as a test for language performance.

Rust programs created using traditional threads, async with Tokyo, and async with async-std.

Go routines as the building block for concurrency without separate implementation.

Java's introduction of virtual threads in JDK 21, similar to Go routines.

C#'s first-class support for async-await and its synthetic thread implementation.

Node.js's memory consumption is significantly lower due to its event loop and timers.

Python's asyncio and its surprisingly low memory footprint.

Elixir's async capabilities and its memory consumption at one million tasks.

Hardware used for testing: Xeon processor and its implications for results.

Rust and Go programs compile to static binaries and have a smaller memory footprint.

Managed platforms and interpreters consume more memory compared to compiled binaries.

Surprise that .NET has the worst memory footprint, suggesting potential for tuning.

Observation that native threads are more memory-intensive than async tasks or virtual threads.

C#'s competitive performance in memory consumption even at one million tasks.

Go's loss of advantage over Rust in memory consumption at higher task counts.

The importance of considering task launch time and communication speeds in benchmarks.

Call for more comprehensive benchmarks involving real-world tasks like websocket connections.

Transcripts

play00:00

how much memory do you need to run one

play00:03

million concurrent tasks

play00:06

by the way alerts are off

play00:09

uh uh in this blog post I delve into the

play00:12

comparison of memory consumption between

play00:13

asynchronous and multi-thread programs

play00:15

across popular languages like rust go

play00:16

Java C sharp

play00:19

Python node.js and of course everybody's

play00:23

favorite

play00:25

these nuts uh sometimes ago I had to

play00:27

compare performance of a few computer

play00:29

programs designed to handle a large

play00:30

number of network connections I saw a

play00:32

huge difference in memory consumption of

play00:33

those programs even exceeding 20x

play00:36

okay that I mean it makes sense it will

play00:39

you know how are they handling things

play00:40

because I can go it's pretty it's pretty

play00:42

slick goes pretty dang pretty dang slick

play00:45

you know what I mean uh some programmers

play00:47

consume little over 100 megabytes but

play00:49

others reach almost uh three gigs I

play00:51

think what he's trying to say here I

play00:52

think what Peter what old Peter up there

play00:55

kalaskowski is trying to say is that

play00:58

node.js

play01:01

node.js loves the memory okay at 10K

play01:03

connections unfortunately those programs

play01:05

were quite complex and differed also in

play01:07

features so it'd be hard to compare them

play01:09

directly and draw some meaningful

play01:10

conclusion as that wouldn't be an apple

play01:12

to Apple comparison this led me to an

play01:14

idea of creating a synthetic Benchmark

play01:16

instead

play01:19

synthetic by the way I actually do want

play01:21

to like follow this this little line of

play01:23

thought right here so I want everyone to

play01:25

pay really close attention if you go to

play01:26

github.com the primogen right uh

play01:32

and you look at this and you go to my

play01:36

latest one is they're like yeah not left

play01:38

pad there we go TS is rust zigds I guess

play01:41

I'm I'm going through a D's face okay uh

play01:44

if you go here you can join and add your

play01:46

own language we're building The

play01:48

Interpreter okay

play01:52

and then I want to test it I actually

play01:53

want to build a server that does like

play01:55

full interpretation and we'll figure out

play01:57

what the what the rules are and all that

play01:59

but actually can compile remotely right

play02:02

and then that is what language can do

play02:05

that the fastest I feel like that is a

play02:07

way cooler

play02:08

like test of languages than these dumb

play02:10

tests that you see right there's that

play02:11

one YouTube video that did like uh that

play02:13

just did like a mathematical formula and

play02:15

be like which one does this one the best

play02:17

and it's just like it but that's not

play02:19

even like real at all okay you're not

play02:20

even creating memory we need like memory

play02:22

you need cleanup you need things that

play02:24

happen you need connections you need sys

play02:26

calls you want to see the entire you

play02:29

know the entire thing you don't want to

play02:31

just see like just some tiny little

play02:33

nothing you know what I mean it never

play02:35

works that way it's always a lie it's

play02:36

just a lie it's just always alive

play02:38

anyways let's do this

play02:41

we have Microsoft guy yeah Benchmark I

play02:43

created the following program in various

play02:45

programming languages let's launch and

play02:46

concurrent tasks for each tack waits for

play02:49

10 seconds and then the program uh

play02:51

exists after all the tasks finished what

play02:54

the program continues to exist after we

play02:57

are finished

play03:00

I'm pretty sure this is like a fork bomb

play03:02

then uh the number of tasses controlled

play03:04

by the command line argument let's go

play03:06

let's go the little help of chat

play03:08

Jeopardy I could write such programs in

play03:10

a few what

play03:12

what

play03:14

what do you mean

play03:18

this is not hard in Rust I mean are you

play03:20

using a real threat are using Hardware

play03:22

threads or green threads or go that

play03:24

simple Java this is probably not that

play03:26

hard to probably do it in a few moments

play03:27

of just a what do you mean chat Jeopardy

play03:29

see this seems like such a crazy

play03:31

crazy things people just love them Chad

play03:33

jeopardies uh anyways rust I created

play03:35

three programs in Rust the first one

play03:36

uses traditional threads

play03:38

that's what I wanted to see okay I

play03:41

wanted to see one Hardware in one

play03:43

language traditional threads okay I'm

play03:45

sick of all this polyphretisms going on

play03:48

uh here's the core of it bam make it

play03:51

happen uh the other two versions had

play03:53

async with Tokyo and the other with

play03:55

async stood

play03:58

here's the core of the Tokyo beautiful

play04:00

beautiful

play04:02

I like this the async stud uh variant is

play04:04

very similar so I won't put it there go

play04:06

uh go routines are the building block

play04:07

for Conservancy so we don't need to do

play04:09

them separately uh but we used a weight

play04:10

group okay beautiful great use of a

play04:12

weight group by the way this is a great

play04:14

use of a weight await group loved it

play04:16

loved every part of this uh again I

play04:18

think go for all of its downfalls also

play04:21

has a lot of updrafts what's what's the

play04:23

term for like

play04:25

what's the opposite of a downfall

play04:28

yes I did have a bad experience with C

play04:30

sharp why you bring that up okay

play04:33

an upfall an upwind an updraft

play04:35

an uplift

play04:39

a boob job what do we call it

play04:41

I don't even know

play04:43

Java Java traditionally uses threads but

play04:45

JD jdk 21 offers a preview of virtual

play04:49

threads which are similar concept to go

play04:51

routines look at Java go

play04:54

Java has almost caught up to 2015. I

play04:57

think we all need to be impressed right

play04:58

now can we just take a moment to realize

play05:00

that Java's going places it really is

play05:04

like this is incredible

play05:06

I mean the next thing you know

play05:08

they I mean the next they could actually

play05:12

beat C plus plus by the time C plus plus

play05:14

23 comes out Java might actually be

play05:17

exceeding what happened in 2023 as far

play05:20

as technology Technologies go it could

play05:22

be it could be incredible and I think

play05:24

you guys are just not even considering

play05:25

how amazing this is all right uh let's

play05:28

see list of threads new arraylist good

play05:30

choice of arraylist uh you did not

play05:31

create you know a little alarming that

play05:34

you didn't you know pre-populate the

play05:35

size here you knew how big it was going

play05:37

to be a bunch of things new threads all

play05:40

right a little sleep little truck catch

play05:41

uh does it so he's not counting one

play05:44

thing I'd be a little careful of is even

play05:45

though you don't need to there is no

play05:47

counting right here going on right how

play05:50

many times did this fail I think that's

play05:51

really important to think about

play05:52

you know just in case when you're

play05:54

creating these tests you you need to do

play05:55

that okay

play05:57

um thread start thread add let's go

play05:59

thread join perfect beautiful I'm

play06:01

curious about this as well

play06:03

when you go individual thread joins this

play06:06

could be bad right am I am I right on

play06:08

this one this could actually have a a

play06:10

greater Slowdown

play06:12

because you're you're doing it one at a

play06:14

time and so you could have already had

play06:15

like a hundred finished that you like

play06:17

aren't

play06:18

you know what I mean that's a race yeah

play06:21

yeah I feel like this is

play06:23

it's blocking I know that but it's it's

play06:25

not just blocking us that you could pay

play06:27

a huge penalty up front and then you'll

play06:30

have this whole thing where you have to

play06:31

go through each one and I assume also

play06:32

join is like not a free call

play06:34

I assume it's like a sis call is that

play06:36

fair

play06:37

I don't know I don't know what it takes

play06:38

to do a join but my my assumption is

play06:40

that it's a non-trivial cost

play06:43

uh

play06:44

you know what I mean yeah anyways just a

play06:46

thought just a thought but I guess if

play06:47

they're green threads maybe that's not

play06:49

the case maybe they're actually really

play06:50

fast and delicious you know what I mean

play06:53

I don't know anyways these are just my

play06:55

thoughts I'm just kind of raw dogging my

play06:57

thoughts out here okay uh here's the the

play06:59

variant with virtual threads uh notice

play07:01

how similar they are oh nice that's

play07:03

beautiful well done oh I guess these

play07:04

ones are Hardware ones and the other one

play07:06

these ones are Hardware ones these ones

play07:08

are oh my goodness I'm scrolling way too

play07:09

fast oh my goodness I'm gonna vomit

play07:10

these ones are virtual ones beautiful

play07:12

still doing that I don't like that C

play07:14

sharp is similar to rust has first class

play07:16

support for async await awesome so there

play07:18

we go we're gonna do a little task run

play07:19

right here so this must be uh okay so

play07:23

this has to be

play07:27

those have to be synthetic thread so

play07:29

we're not actually getting so C sharp is

play07:30

not doing Hardware thread so there does

play07:32

need to be like a a disambiguation here

play07:34

which one's doing like actual actual

play07:36

threads versus which ones are doing some

play07:38

sort of managed environment because I

play07:40

would assume that the managed

play07:41

environment this is where a managed

play07:43

environment does amazing right

play07:47

right I think so

play07:50

you can do both

play07:53

well I would assume whenever you see

play07:55

something like uh async await usually

play07:56

there's some sort of whole managed

play07:58

environment that goes into it

play08:00

usually right because if you're not

play08:02

doing it yourself there's something else

play08:04

going on you know what I mean I feel

play08:05

like uh the managed environment would be

play08:07

slower no because Hardware Hardware

play08:10

threads are expensive

play08:12

right uh node.js util's promise file

play08:15

okay so again you don't want to do this

play08:17

I feel like there is a little something

play08:19

there you got to be careful about you

play08:20

know maybe a little extra garbage

play08:22

collection going on I don't know but

play08:23

they're probably fine probably not a big

play08:24

deal probably enough probably not oh my

play08:27

goodness

play08:28

probably not enough to be too upset

play08:31

about it uh python

play08:34

I don't know what delay is delay must

play08:36

just be a function that returns a

play08:39

oh set timeout oh yeah okay yeah yeah

play08:41

I'm dumb I'm dumb this is also a syntax

play08:44

error

play08:45

guys

play08:47

syntax error right there okay watch your

play08:51

parents okay don't you should make sure

play08:53

you always just put code up on an

play08:54

article that's just like it works always

play08:56

make sure I mean I've done it too we've

play08:58

all done it just make sure it works

play08:59

right okay so this is looking good uh

play09:01

python out of days think of weight in

play09:03

three five nice okay look at this

play09:05

asyncio a sinkio there we go beautiful

play09:09

uh that all looks great Elixir is famous

play09:12

for async capabilities as well let's go

play09:15

I love to see it uh task await mini

play09:17

until infinity and beyond

play09:21

you know I really hate that phrase by

play09:23

Buzz Lightyear to infinity and beyond

play09:26

wouldn't you not be at Infinity if you

play09:29

could go beyond the point of infinity

play09:34

isn't that just like not Infinity like

play09:36

can we be real here

play09:41

that's the joke

play09:46

uh it's true also Infinity yeah I know

play09:49

thank you Deep Thoughts with me

play09:51

just letting you know deep thoughts all

play09:52

right test environment Hardware Xeon

play09:54

this thing okay

play09:56

um this is starting to look like a

play09:58

personal computer which again gotta be a

play09:59

little careful uh rust 169 nice go

play10:03

eighteen one

play10:05

nice jdk

play10:08

uh dot net node

play10:11

python Elixir let's go all programs were

play10:14

launched uh using release mode if

play10:16

available other options were left uh

play10:18

default

play10:19

all right minimum of footprint let's

play10:20

start with something small because some

play10:22

of the runtimes requires uh some memory

play10:24

for themselves yep that's right yep here

play10:26

you go this makes sense though because a

play10:28

node would be really really large well

play10:30

c-sharp requires a 131 megabytes for

play10:33

just nothing

play10:36

what

play10:38

like I get that there's like a whole

play10:41

thing going on but that's just a lot

play10:45

I mean this all seems about in line with

play10:47

node right C sharp I I would what does C

play10:50

sharp do that requires three times the

play10:52

amount of telemetry information that the

play10:54

other ones do

play10:56

uh okay it's pindos anyways so go make

play11:00

sense rust all these things make sense

play11:01

right because they all should be really

play11:02

really small because they're actually

play11:04

you know these are actually like

play11:05

compiled thingies but I would like to

play11:07

say that this is really impressive for

play11:10

go I want you to take a a moment about

play11:12

this

play11:13

this includes a garbage collector

play11:16

okay like things are running here

play11:22

that's really good that's really really

play11:24

good good job go good job go that's

play11:26

really really good the surprise hero is

play11:28

python it shouldn't be surprising uh oh

play11:30

I mean I guess it's surprising in the

play11:31

sense that it's half the it's half the

play11:33

memory of I I guess I would have I guess

play11:35

in my head I would have probably put it

play11:36

the same as Java or node.js uh Elixir

play11:39

also a little surprising and so large

play11:41

interesting

play11:43

um

play11:43

I wonder how he's getting the memory is

play11:45

he using vmrss what does he use in here

play11:47

uh we can see there's our certainly two

play11:48

groups of programs go and rust programs

play11:50

compile statically to Native binaries uh

play11:52

need very little memory Yep this makes

play11:54

sense the other programs running on

play11:55

managed platforms and or let's see or

play11:57

through interpreters consume more memory

play11:58

although python fares really well in

play12:00

this case there is about an order of

play12:02

magnitude difference in memory

play12:03

consumption between these two groups yep

play12:05

uh it is a surprise to me that.net

play12:07

somehow has the worst footprint but I

play12:08

guess that uh this can be tuned with

play12:10

some settings maybe let me know in the

play12:12

comments okay this is good it's good

play12:13

that he's stating where he's a little

play12:15

bit surprised about I like to see that

play12:17

all right so 10K tasks before I oh no oh

play12:20

no you can see you can see what's

play12:21

happening here all right so let's see

play12:23

rust threads this this makes this makes

play12:26

perfect sense right it is expensive

play12:29

so I guess one thing that they we didn't

play12:31

specify here or that he didn't speak

play12:33

about with these two right here which

play12:36

was how much

play12:39

worker threads were created

play12:43

right

play12:44

so I don't know what Tokyo does

play12:47

but there is definitely something to

play12:49

that right uh threat stack size right

play12:51

yeah there's a there's a lot here that

play12:53

might be hidden that we may not be uh

play12:55

considering correctly there's just it

play12:58

just looks really small which it may not

play13:00

be this again this is one of the

play13:02

problems about making a really really

play13:04

small synthetic test is that you don't

play13:06

know what's going to get you this makes

play13:08

more sense this is something I I guess I

play13:10

I can believe go being this uh just

play13:12

because go does have a whole managed

play13:14

system around it and so this is good

play13:17

this is still great this is less than

play13:18

what it took a thousand or ten thousand

play13:21

go threads go routines go go co routines

play13:25

uh is less memory

play13:27

than node.js by itself right so it's

play13:30

pretty good

play13:31

pretty dang good I like to see this uh

play13:33

let's see Java virtual threads yeah this

play13:35

makes sense I'm a little bit surprised

play13:36

that Java is that big for regular

play13:38

threads right uh C sharp I assume

play13:40

doesn't change much yeah it doesn't

play13:42

change pretty much at all because again

play13:43

it's probably doing the same Tokyo thing

play13:45

that's going on here added nothing

play13:49

all right

play13:51

so this makes sense

play13:53

uh virtual threads also this is you know

play13:56

slightly in line this is more in line

play13:57

with go I guess uh note I'm very

play14:01

curious how that one I guess it's

play14:03

because set timeout is not really

play14:05

so one thing that he did not do

play14:07

correctly is it's not

play14:09

no doesn't really have this concept of

play14:11

threads right I I guess maybe the most

play14:14

correct way you could do this would be

play14:17

do would to do something like

play14:19

uh worker workers right

play14:22

and the reason why this is kind of odd

play14:24

is that node just creates a uh a a event

play14:29

Loop item

play14:30

and that event Loop item is probably

play14:32

some very small piece of information my

play14:34

guess is that especially since the timer

play14:35

is probably a time for when it's done

play14:37

and a pointer to a function to call

play14:39

right it's like going to be a pretty

play14:41

dang small amount of memory

play14:43

and so this makes sense that node really

play14:45

doesn't do much because you actually

play14:46

didn't create multiple threads

play14:49

you created 10 000 timers which is much

play14:52

much different uh because all of these

play14:55

through here they can they can also uh

play14:58

execute with parallelism

play15:01

you know what I mean

play15:02

there's parallelism that can go on in

play15:04

these that cannot happen in node.js

play15:06

therefore they're not really equal so

play15:08

it'd have to be worker threads you'd

play15:10

have to use something like worker

play15:11

threads I don't know if python has the

play15:12

same parallelism problem I don't really

play15:14

know how python works and I also don't

play15:16

know how Elixir works but good job

play15:17

elixir

play15:19

right

play15:20

I said parallelism parallelism

play15:22

intentionally because these can all

play15:23

execute with parallel parallelism

play15:25

parallel parallelism depending on how

play15:28

many worker threads where's Gradle great

play15:30

question

play15:31

all right few surprises uh everybody

play15:33

probably expected the threads would be a

play15:36

big loser of this Benchmark and this is

play15:37

true for Java threads which indeed

play15:39

consumed about 250 megabytes of ram the

play15:41

native Linux threads used uh from rust

play15:43

seem to be lightweight enough that the

play15:45

10K threads of memory consumption is

play15:46

still lower than the idle memory

play15:48

consumption of many other runtimes async

play15:50

tasks or virtual green threads might be

play15:52

lighter than native threads

play15:54

I would say might is I mean observably

play15:57

probably true is what we're seeing here

play16:00

right I'd say it's observably true uh

play16:03

but we don't see the advantage at uh

play16:05

only 10K tasks we need more tasks

play16:07

okay another surprise here is go uh go

play16:10

routines are supposed to be very

play16:12

lightweight but they're actually

play16:13

consumed more than 50 of the ram

play16:15

required by rust threads honestly I was

play16:17

expecting much bigger difference in

play16:18

favor of go hence I conclude uh conclude

play16:21

that 10K current tasks threads are quite

play16:23

competitive alternative Linux kernel uh

play16:25

definitely does something right here

play16:27

huh

play16:29

again I don't again I I'm not sure how

play16:32

much I buy this I don't know I don't

play16:34

know what go does

play16:38

you know what I mean I don't know what

play16:39

go does that makes this good or bad go

play16:42

maybe reserving more memory it may have

play16:45

different parameters than something like

play16:47

Tokyo does and so

play16:49

again I don't know how fair this is to

play16:51

say that rust greatly outperformed it

play16:52

because it's not doing anything too much

play16:55

Telemetry too much Telemetry all right

play16:57

go also has lost its advantage over rust

play16:59

Ace uh async in the previous Benchmark

play17:01

it now consumes over six more times more

play17:03

memory than the best rust program which

play17:05

is also taken by python yeah the final

play17:07

surprise is that 10K task memory

play17:09

consumption.net didn't significantly go

play17:11

up uh from the idle memory used yeah

play17:12

again

play17:15

Telemetry now uh Telemetry it's actually

play17:17

just Telemetry uh probably it just uses

play17:19

pre-allocated memory or its idle memory

play17:21

is just so high uh that it 10ks didn't

play17:23

yeah it didn't matter okay 100 000 tasks

play17:26

okay let's do this let's see uh so the

play17:29

thread benchmarks could be excluded

play17:30

probably this could have somehow tweaked

play17:32

by changing uh system settings but after

play17:34

about an hour I gave up so hires a

play17:36

hundred thousand tasks

play17:39

okay so yeah you can't spawn non there

play17:42

you go so this is a good notice that all

play17:45

non-green uh threads have all gone away

play17:49

so I I guess my guess is that his

play17:50

program kept crashing he probably I

play17:52

would assume your U limit you should be

play17:54

able to do you I don't know if there's

play17:55

like I don't know what the potential

play17:58

requirements are that you can't spawn a

play17:59

hundred thousand threads but my guess is

play18:01

that you just Fork bomb yourself and it

play18:03

explodes and dies

play18:04

um all right so Tokyo's gone up this has

play18:07

gone up this has gone up like to me this

play18:10

is pretty these are all pretty fine

play18:12

again I really doubt C Sharp's doing

play18:14

something right something about C sharp

play18:16

tells me that this is not executing the

play18:18

way you think it is

play18:20

can we all agree that this is not doing

play18:22

what you think it is

play18:27

there's no way that you just did ten

play18:30

thousand there's no way that you did one

play18:32

to ten thousand to a hundred thousand

play18:34

with absolutely no memory change

play18:36

something is being clever here

play18:40

right something's being very clever

play18:43

or C sharp is probably the best

play18:46

no Jazz so C Sharp's gonna win I hope

play18:48

everybody sees this coming right

play18:51

I hope everybody sees this coming that C

play18:53

sharp is gonna start beating out some

play18:55

Rust if they keep going with thread

play18:56

limits all right at this point go

play18:57

program has been beaten up uh not only

play18:59

by rust but also by Java C sharp and

play19:01

node.js uh though let's see and

play19:03

linux.net likely cheats because it's

play19:05

memory uh you still isn't going up I had

play19:07

to double check if it really launches

play19:09

the right number of tasks but indeed it

play19:10

does and still uh exits after about 10

play19:13

seconds uh it doesn't block the main

play19:15

Loop okay I would still

play19:18

I would argue you need to do something

play19:21

I bet you this will greatly change in C

play19:23

sharp if you had like a

play19:26

a concurrent hash map that every one of

play19:28

those tasks try to add one item to and

play19:30

read one item from I think it would just

play19:32

completely

play19:33

change the memory wildly right

play19:40

uh let's say okay one million tasks

play19:42

let's go extreme extreme extreme extreme

play19:46

all right add one million tasks a Lister

play19:48

gave up okay nice system limit has been

play19:51

reached okay edit some commenters

play19:53

pointed out that I could have increased

play19:54

the limit yep U limit after adding Arrow

play19:57

P plus bajillion uh to Elixir it ran

play20:00

fine okay nice

play20:01

all right let's see what we got here

play20:04

nice look at look at that C sharp oh

play20:07

memory did go up this time

play20:09

so that's interesting C Sharp's memory

play20:11

did go up

play20:14

I wonder why this 10x caused memory to

play20:17

go up but the other two 10xes didn't

play20:21

sus and C Sharp's the best everybody

play20:23

finally we see an increase in memory

play20:25

consumption of the c-sharp program but

play20:27

still very competitive it even managed

play20:28

to slightly beat one of the rust run

play20:30

times the distance between go and the

play20:31

others increase now go loses over 12x to

play20:34

the winner it also loses 2x to Java

play20:37

Java which contradicts a general

play20:39

perception of jvm being a memory hog and

play20:41

go being lightweight

play20:48

hey

play20:49

Russ Tokyo remained unbeatable this

play20:52

isn't surprising after seeing how it did

play20:53

100K tasks final word as we observed a

play20:56

high number of concurred tasks actually

play20:57

I want to have a final word first okay

play20:59

I'm having the final word first first

play21:01

off I don't know if I like this

play21:02

Benchmark I love the idea I don't know

play21:03

if I love The Benchmark I feel like you

play21:05

need to do more things right I really do

play21:08

feel like you need to do more things for

play21:09

this to be real because something is

play21:11

wrong here first off one thing about

play21:13

c-sharp and memory that they're

play21:15

completely just disregarding along with

play21:17

Java is garbage collection along with

play21:19

node along with go like all of these

play21:21

have garbage collection so does python I

play21:23

assume elixir does too but I mean Elixir

play21:25

has already had four gigs am I right am

play21:27

I right

play21:29

um but

play21:30

that's where rust is gonna really shine

play21:32

is that if you're just measuring memory

play21:34

doing something that creates and uses

play21:37

memory these other ones are going to

play21:39

really struggle but I wonder how much go

play21:40

is going to struggle because go gets the

play21:42

best of Two Worlds it gets a managed

play21:44

memory environment but it also gets like

play21:46

the smallness of rust when it comes to

play21:49

usage of memory so when you create a

play21:50

struct you're getting like a smaller

play21:51

structure you're not getting a node.js

play21:53

struct which is just much different

play21:54

right an object in node is not going to

play21:57

be nearly as lightweight as an object

play21:59

and go it's just that's how it works and

play22:02

so there is like it's kind of

play22:03

interesting you know what I mean

play22:05

it's just it's just interesting that

play22:07

doing nothing this is the results but I

play22:09

just don't believe it because my guess

play22:12

is that this Elixir number four

play22:14

gigabytes is likely what would happen to

play22:17

a lot of these if you did that

play22:19

all right final word

play22:22

what is wrong why do I keep having like

play22:27

uh as we have observed a high number of

play22:28

concurrent tasks can consume a

play22:30

significant amount of memory even if it

play22:32

did not do not perform complex

play22:33

operations yeah I mean it makes sense

play22:34

like just imagine that every single

play22:36

imagine that every single task ran

play22:39

requires a hundred bytes of memory

play22:42

that would be a hundred that'd be 100

play22:43

megabytes at a million right so it

play22:46

likely is going to require more than

play22:47

that yeah stack size you got all sorts

play22:49

of stuff it requires probably more than

play22:51

100 bytes therefore it makes sense this

play22:54

makes sense right

play22:57

this is like what's a million times 4K

play22:59

right if you had 4K stack size boom you

play23:02

got that right

play23:03

uh anyways let's see conversely other

play23:05

run times with high initial overhead can

play23:07

handle High workloads effortlessly

play23:10

C sharp for the win by the way by the

play23:11

way the big takeaway here is you should

play23:13

just use C sharp we're all C sharp Andes

play23:15

now inside this stream I hope

play23:17

everybody's ready for the C sharp Arc C

play23:18

sharp Arc everyone excited for it I'm

play23:21

excited for it

play23:23

um I think that c Sharp's obviously the

play23:25

best language okay I've been telling you

play23:26

guys this for so long now and honestly

play23:29

this chart just proves how good C sharp

play23:32

is okay you guys kept always talking

play23:34

about how great go is look at how

play23:36

terrible go is 2.6 gigabytes

play23:40

okay you just don't understand things at

play23:44

all all right C sharp clearly best

play23:47

language

play23:48

clearly best language the comparison

play23:51

focused solely on memory consumption

play23:52

while other factors such as task launch

play23:54

time and communication speeds are

play23:55

equally important notably at one million

play23:58

tasks I observe that the overhead of

play23:59

launching tasks became evident and most

play24:01

programs required more than 12 seconds

play24:03

to complete stay tuned for upcoming

play24:05

benchmarks where we'll explore

play24:06

additional aspects in depth I'd love to

play24:08

see this except for instead of doing

play24:09

node.js just doing timers let's set

play24:11

worker threads I'd love to see some sort

play24:13

of computation model added to everything

play24:14

I personally just think that the best

play24:16

way to do this is to do some sort of

play24:19

longer run living task right how many

play24:22

websocket connections can you make how

play24:24

effectively how many open TCP

play24:26

connections can you make to a server and

play24:28

then just start sending something back

play24:29

and forth how much can you do in a

play24:32

language not like these because you know

play24:35

the reality is you don't use a language

play24:37

to launch a timer you use a language to

play24:39

do something and I feel like a

play24:41

websocket's like a really great kind of

play24:44

uh

play24:45

it's a really great simple way to test

play24:48

something because it is it's just a TCP

play24:50

connection you have to do a moderate a

play24:52

pretty small amount of work to parse out

play24:53

a frame

play24:54

it shows what garbage collection does to

play24:56

the system uh it shows what kind of the

play24:58

interacting with with the system calls

play25:00

does to a system and then if you have

play25:02

anything extra on the system such as

play25:04

like if you do a chat room it will you

play25:06

know if you have to for each over

play25:08

clients what do four Loops do to your

play25:09

program it's very very interesting uh

play25:11

even with node.js the difference like if

play25:13

you build a chat client

play25:15

and all it is is a chat line to where

play25:17

websocket connections can join in make a

play25:20

simple request to join rooms and then

play25:22

send messages to the room a for each

play25:25

statement will effectively cut your RPS

play25:28

in half when you're iterating over the

play25:30

available sockets

play25:34

or it's not RPS it's MPS messages per

play25:36

second pretty wild that that can happen

play25:38

right and so it's it's pretty wild that

play25:42

even such a simple small little thing

play25:44

can have such a huge impact

play25:47

on performance

play25:49

anyways just something to think about

play25:53

anywho all right hey great article

play25:54

though great article everybody hey

play25:56

everybody great article hey great

play25:59

article everybody everybody

play26:01

give a little clap for Peter good job

play26:03

Peter appreciate the work you put in

play26:10

what is the name

play26:14

you know what the hell the name is the

play26:16

name

play26:19

is the primogen

Rate This

5.0 / 5 (0 votes)

相关标签
Memory ConsumptionConcurrencyProgramming LanguagesBenchmarkingRustGoJavaC SharpNode.jsPythonElixir
您是否需要英文摘要?