I don't think I even saw this until I published the article. I don't think it was academically published, or googled well back in 2000. Nor did it match my needs for a ring buffer at the time, which was to drop stale data (I think in that algorithm, write operations fail when the buffer is full), so if I did see it, I wouldn't have payed enough attention to notice if it even had users. It's good work for sure, but that's why it didn't get mentioned.
Eh, I get it. I also independently came up with these MPMC approaches before hearing about LMAX. They're not entirely trivial but they do follow fairly naturally from the problem space when you really think about it. It's a good piece of engineering, but the one thing that's really unique about LMAX is the amount of advertising it gets.
> the one thing that's really unique about LMAX is the amount of advertising it gets.
Virtually zero? I have to go out of my way to remind HN it exists while everyone is 300+ comments deep into reinventing the wheel on a ~quarterly basis.
Right buffer is a relative obvious and simple idea. For some reason the Java-OOP crowd keeps thinking that LMAX deserves a nobel price for being neither first nor last to use it.
> have to go out of my way
Yeah, that's exactly the annoying part. Can't mention ring buffer ever without someone bring up LMAX. "But do you know, that some Java developers somewhere once wrote something that didn't completely ruin the hardware performance?! It's stunning and amazing."
IMO the take-away from LMAX is not ring buffers - it's the knowledge of how much useful work a single CPU core can do. It's a story of playing to hardware's strengths instead of wrapping yourself up in bullshit excuses. They realized their problem was fundamentally not parallelizable, so they wrote it to run serially as fast as possible instead of wrapping themselves up in bullshit excuses, and the resulting performance was much faster than anyone would have ever guessed if they hadn't done it.
I am not sure why this is annoying. Some problems can be solved comprehensively. This is a pretty good example of one. It might be better for us to focus our attention on other aspects of the problem space (the customer/business).
There are a lot of algorithms that get passed around in java because they can deal only with pointers and pretend memory allocation and deallocation doesn't exist and doesn't lock. I'm not convinced it actually makes sense to use java as a reference language for lock free algorithms because it expose all the details.
Weird to see this here! I've used CoralBlocks in the low-latency trading domain previously. Highly recommend. The API is kind, they're very responsive, and the latency is exceptional (and comes with all the basics like thread pinning built-in for convenience)
I think you can take a look at the DiamondQueue, which is a Demultiplexer and a Multiplexer combined so that thread A dispatches a bunch of tasks to a fixed set of worker threads (W1, W2, W3, etc.) and then these worker threads use a Multiplexer to deliver the results to another thread B. Thread A and Thread B can also be the same thread. There is an example here => https://www.coralblocks.com/index.php/the-diamond-queue-demu...
The DiamondQueue should be soon available for free at the CoralQueue project on GitHub.
>any recommendations for a low latency work queue (with in a jvm)?
I toyed around the ring buffer pattern a decade ago, creating a unicast one (using CAS on entries, and eventually a logarithmic scan for next readable entry, not to brute-force-scan them all), but I'm not sure that its latency is much better than that of a regular ThreadPoolExecutor (the throughput could be better though).
Latency also depends on whether it spins or blocks when waiting for a slot to read or write.
The Dacia Sandero unfortunately gets a 2 star Euro NCAP rating (which is typical for Dacia cars). Not something I personally would feel safe putting my family into!
> The Jogger returned the equivalent of a four-star rating for adult occupant crash protection, and three stars for child occupants. Plenty respectable scores. The Jogger lost marks, however, for its lack of active safety equipment: it doesn’t offer lane-keep assist, pedestrian detection, or seatbelt warnings for the rearmost row. [0]
> The overall NCAP rating is dictated by the lowest score in any individual category, hence that headline one-star result for the Jogger.
Many people actively disable gimmicks like "lane-keep assist", so YMMV on such damning "1 star Euro NCAP rating".
A year or so ago, my son needed a tool for making really simple minecraft plans. All the drawing tools out there he could find were overly complex or weren't 'quite right' for him, so I took the opportunity to learn some web and javascript stuff and made this: https://draw.pixelweasel.com/
One outstanding 'todo' was textures!
Then I wanted to make ASCII art automatically from any picture, so I played around and made this: http://ascii.pixelweasel.com/ (again, playing with javascript)
Super cool. Love the interface, was not expecting to be thrown back a few decades!
On mobile, I tried recording to /c/PepTalk, but after recording my voice, none of the buttons ('save', 'play' or 'stop') did anything. So I wasn't sure if it had actually uploaded.
Then when I went back to the /c/PepTalk channel to check I had a popup saying something like 'failed to fetch waves' (sorry, I don't recall the exact error message!).
I'll keep an eye on this ongoing though, as I adore the concept.
That's a big part of it. But their scale and presence also means they get to do things that have been invaluable for us, like being able to book meeting rooms in and have access to other WeWork premises with low effort.
Spreadsheets are phenomenally flexible, but they obviously don't scale well or behave nicely with source control.
I work at Anaplan, and the most common way that our biggest customers discover us is when they've been bitten by spreadsheets as they've scaled, and now they have users emailing spreadsheets around and someone with a full time job collating them.
We've modelled the product around the flexibility, but rigor and scale on top of it.
I don't speak fluent maths, but i'm extremely interested. Is anyone in a position to explain what the initial equation for U(x) means?
I'll be in your debt forever!
A Lipschitz function is one that doesn't change to quickly, such that the difference between two values |f(x) - f(y)| is at most as large as the distance between x and y times a constant k i.e. |f(x) - f(y)| <= k|x-y|. In particular this implies that:
f(x) - f(y) <= k|x-y|
hence
f(x) <= f(y) + k|x-y|.
Therefore the function:
u(x) = f(y) + k|x-y|
is an upper bound for the function f(x). Repeating this for multiple points x1, x2, x3,... you can construct a stricter upper bound by taking the minimum:
U(x) starts by evaluating f(x), but instead of checking for every value of x, it only checks certain values x1, x2, x3... xt. Then U(x) gives an upper bound for what f(x) might be for any x between the ones you actually calculated. Take the difference between any x and the nearest xi for which you know f(xi), and multiply it by the maximum possible slope. Add that to f(xi), and you have the upper bound for how high f(x) might be.
Consider the case where f is an elementary function of one variable and you know that its slope between any two points is at most k and at least -k. And suppose you want an upper bound on f(0) but you know the values of f(-2) and f(3). Then f(0) <= f(-2) + 2 * k and f(0) <= f(3) + 3 * k. Taking the minimum of these two right-hand sides leads to a formula analogous to the one for U(x) that you're asking about (with the norm || x - x_i || taking the place of |0 - (-2)| and |0 - 3| in our example).
if you can program, you can read maths (understanding its purpose is a different issue)
this formula defines a function U(x). This means that it gives a recipe that takes a number x and produces a number U(x). The recipe depends on an already prepared set of ingredients: a set of numbers x1, x2, ..., xt, k, and another function f. Now, given a number x, to compute U(x), you first compute all the numbers f(xi)-k*|x-xi|, and then you pick the smallest one. This smallest value is then U(x).
The graph below the formula displays its interpretation. The graph of the function f is the red curve, the points (xi, f(xi)) are the black dots, and U(x) is in green.
The doc uses x to refer to the new point, and x_i for the ith previously evaluated point. To reduce ambiguity, i'll use a capital X to refer to the new point.
The equation says that U(X) is equal to the minimum value of the expression f(x_i) + k * (Euclidean distance from x to x_i), where i ranges over integers 1 to t.
In Go pseudo-code:
func U(X []float64, x [][]float64, f func([]float64) float64, k float64) float64 {
min := math.Inf(1)
for _, x_i := range x {
e := f(x_i) + k * EuclideanDistance(X, x_i)
if e < min {
min := e
}
}
return min
}
It's interesting that the article doesn't delve into non-Asian martial arts like Krav Maga, which, in my limited experience, offers an extremely reductionist 'does it work' mentality.
Interesting also that the gold standard of the article is 'in the ring'. I would have thought messy 'real world' combat is gold standard (but obviously less reproducible, from the science perspective). Additionally, multiple opponents.
As someone who does martial arts (ranging from muay thai to aikido) if it doesn't work in the controlled environment of the ring it often won't work in the messy environment in the world. Krav Maga is really variable in quality and the best gyms are still ones that have a lot of "aliveness" in training, which is generally sparring or some close facsimile thereof.