35

Could someone suggest good CircularBuffer implementation? I need both "not thread-safe" and "thread-safe" versions. I expect following operations:

  • ability to provide size of the buffer when creating
  • adding elements
  • iterating elements
  • removing elements while iterating
  • probably removing elements

I expect implementation to be highly optimized in terms of speed and used memory, average and worst times etc.

I expect "not thread-safe" implementation to be extremely fast. I expect "thread-safe" implementation to be fast, probably using "lock-free code" for synchronization and it's ok to have some restrictions if this is required for speed.

If buffer is too small to store new (added) element it's ok to silenty override existent element or raise exception.

Should I use disruptor.net?

Adding link to a good example Disruptor.NET example

Community
  • 1
  • 1
Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305
  • Yes, just use [Disruptor.net](http://code.google.com/p/disruptor-net/) they have good results. The disruptor is a concurrency component used to exchange messages between threads (producer consumer) It is optimised for high throughput and low latency scenarios. – Frank Nov 07 '12 at 18:37
  • if disruptor is efficient in "not thread safe" scenario? I can use just regular "array" and write rest methods myself – Oleg Vazhnev Nov 07 '12 at 18:43
  • sure, but you will build your own disruptor...i would not waste my time on that.... – Frank Nov 07 '12 at 19:06
  • if you can add example of the "not thread-safe" disruptor scenario it would be very useful. so far I have found http://code.google.com/p/disruptor-net/wiki/CodeExamples but it contains "multithreaded" version – Oleg Vazhnev Nov 07 '12 at 19:11
  • i've found something here http://stackoverflow.com/questions/8860684/disruptor-net-example – Oleg Vazhnev Nov 07 '12 at 19:17
  • An accepted answer was converted to a comment... that sucks – Frank Nov 07 '12 at 19:36
  • @Frank do you know why it was converted? – Oleg Vazhnev Nov 07 '12 at 19:55
  • @javapowered, This is very sad that some peoples voted to close your question. That is a very nice question for which I'm very happy to have the solution. Thank you!!! By the way' I think answers are not circular... Try: ConcurrentCircularQueue (Multithread). – Eric Ouellet Nov 30 '15 at 00:55

1 Answers1

-6

Not thread safe:

System.Collections.Generic.Queue

Thread safe:

System.Collections.Concurrent.ConcurrentQueue

or

System.Collections.Concurrent.BlockingCollection (which uses a concurrent queue by default internally)

Although technically you really shouldn't use the term "thread safe". It's simply too ambiguous. The first is not designed to be used concurrently by multiple threads, the rest are.

Warty
  • 7,237
  • 1
  • 31
  • 49
Servy
  • 202,030
  • 26
  • 332
  • 449
  • 1
    do you thing .net Queue is using ring buffer? – Oleg Vazhnev Nov 07 '12 at 18:44
  • @javapowered I know that the regular queue is, as it says so on the linked page. As for the concurrent queue, it's probably not strictly using a circular buffer, but it'll be something similar. In any case, the implementation shouldn't matter; that's the whole point. It's logically a queue, and it's implemented with the most efficient algorithm that the .NET team could come up with (which is naturally subject to change if they can improve on it). – Servy Nov 07 '12 at 18:47
  • can I set maximum Queue size so when the queue is full and new element is added the oldest element is automatically removed? I also expect queue to use this "knowledge" that it can't be more than certain size for internal optimizations. – Oleg Vazhnev Nov 07 '12 at 19:01
  • @javapowered The Queue doesn't have that behavior for an initial capacity, but it would be simple enough to wrap it in your own Queue that does. As for BlockingCollection, it *does* allow for a max capacity, but rather than removing an old item it simply blocks you from adding a new item. To change that behavior you would need to, again, wrap it in your own class that provided the altered behavior. – Servy Nov 07 '12 at 19:04
  • 5
    that's why I want true circular buffer. I expect circular buffer to not to use "new memory" at all. this is very handy when it used intensive. – Oleg Vazhnev Nov 07 '12 at 19:05
  • @javapowered It doesn't matter what the implementation is; what you want is to have the `Enqueue` method check the size, and if it's over a set amount to `Dequeue` an item before adding a new one. That functionality can be added regardless of the underlying implementation because it's defined entirely on top of already exposed methods. – Servy Nov 07 '12 at 19:08
  • for me it does matter what implementation is because i'm fighting for the better "tick-to-trade" value of my HFT application :) – Oleg Vazhnev Nov 07 '12 at 19:10
  • All that matters is that the implementation is efficient, not how it accomplishes that. And as for efficiency, start out by actually implementing the solution and benchmarking it. There's no point in spending considerable time and effort re-writing your own queue from scratch because you think you might be able to do it better until you're sure that the library implementation won't work. – Servy Nov 07 '12 at 19:12
  • disruptor is much more faster. about 100 times faster than .net classes. refer https://github.com/LMAX-Exchange/disruptor/wiki/Performance-Results .net implementation is higly not-efficient comparing to disruptor – Oleg Vazhnev Nov 07 '12 at 19:14
  • @javapowered Which is irrelevant if both solutions are fast enough to complete the task at hand. Also note that it's not being compared with the implementations I've mentioned, it's being compared with classes in the java library. – Servy Nov 07 '12 at 19:16
  • @Sevry disruptor is much faster because the way it implemented. .net version must be also faster than microsoft classes. disruptor designed specially for ultra-low latency while microsoft design their classes for general neeeds (often readability and usability is prefered I guess) – Oleg Vazhnev Nov 07 '12 at 19:48
  • @javapowered If you want to use it then that's fine. I'm not saying that you *can't* or *shouldn't*. You're free to use whatever implementation you want. You asked what options were available, and I provided one, which is what I would use were I tasked with this problem. – Servy Nov 07 '12 at 19:50
  • https://github.com/zenith-nz/RingByteBuffer Mine. Hope this helps. – zenith Feb 12 '14 at 11:39
  • 45
    -1 This is a poor answer, since none of the proposed solutions are actually circular buffers (they either expand at will, or run out of space) – piers7 Sep 03 '15 at 00:24
  • 5
    @piers7 Yes, they *are* circular buffers. That they create a new circular buffer when they run out of space and copy the data over doesn't make them not circular buffers. There is no requirement in the question that the data structure in question only ever expand manually, and not never or automatically. If you have such a requirement yourself you're free to ask your own question. – Servy Sep 03 '15 at 12:37
  • 20
    @Servy The .NET queue classes are not circular buffers. They use circular buffers internally, but they are not circular buffers in themselves. Circular buffers are by definition fixed size. – 0b101010 Mar 02 '16 at 14:00
  • To my mind, a circular buffer is one where if you `Next` past the last element, you get the first. But this is the accepted answer, so I guess I either have no idea what was being asked for, or what I'm looking for, or both... – Grimm The Opiner Jan 16 '23 at 08:42
  • Bound Channels might be used for that nowdays – Serg046 Jan 22 '23 at 13:27
  • Besides the growing capacity (which could be taken into account with some extra code), another issue with this answer is that you cannot insert/remove from both ends (as you can in a circular buffer) – Jorge Galvão Aug 10 '23 at 19:16