top | item 42271404

(no title)

aba_cz | 1 year ago

Regarding Java I'm pretty sure that benchmark is broken at least a little bit and testing something else as not specifying initial size for ArrayList means list of size 10 which gets resized all the time when `add()` is called, leading to big amount of unused objects needing garbage collection.

discuss

order

bekantan|1 year ago

It would indeed be better to create appropriately sized storage.

However, I don't think that underlying array is resized every time `add` is called. I'd expect that resize will happen less than 30 times for 1M adds (capacity grows geometrically with a=10 and r=1.5)

fulafel|1 year ago

From the docs: "The add operation runs in amortized constant time, that is, adding n elements requires O(n) time".

Given the linear time time complexity, it seems obvious that adding a thread pointer to the list won't contribute substantially to the thread creation time.

The way these kinds of operations can be implemented for amortized linear time (also in Python, C realloc, etc) is explained in https://en.wikipedia.org/wiki/Dynamic_array#Geometric_expans...

brabel|1 year ago

Yeah that is a junior mistake... They should've pre-sized the ArrayList, or better, used an array because that's more memory efficient (and I would say would be what any decent dev would do when the size of tasks is known beforehand).

> Some folks pointed out that in Rust (tokio) it can use a loop iterating over the Vec instead of join_all to avoid the resize to the list

Right, but some folks also pointed out you should've used an array in Java in the previous blog post, 2 years ago, and you didn't do that.

And folks also pointed out Elixir shouldn't have used Task in the previous benchmark (folk here being the creator of Elixir himself): https://github.com/pkolaczk/async-runtimes-benchmarks/pull/7

sfn42|1 year ago

The difference between an arraylist with correct initial size and an array is almost nothing. Arraylist itself is just a wrapper around an array.