I was trying to figure out why I could write a ring buffer in Go and it would perform so much faster than the equivalent C# implementation.
This is part of the answer. Despite an attempt to align a struct to leverage the cache, it was getting rearranged.
Of course, there is also less inlining and the schedule behind the async command really doesn't like it when you get more active pseudo-threads than cores.
In the end, the data flow TPL was the only implementation that was roughly in the same ball park.