# Spin buffers

**URL:** <https://rubytalk.org/t/spin-buffers/39138>\
**Category:** ruby-talk\
**Created:** [16 July 2007 02:20 UTC](https://rubytalk.org/t/spin-buffers/39138 "2007-07-16T02:20:32Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![John\_Carter](https://avatars.discourse-cdn.com/v4/letter/j/2bfe46/32.png) [@John\_Carter](https://rubytalk.org/u/John_Carter)\
**Post date:** [16 July 2007 02:20 UTC](https://rubytalk.org/t/spin-buffers/39138/1 "2007-07-16T02:20:32Z")

</div>

Hmm. Just being reading the Dr. Dobbs.

I certainly have hit the bottleneck talked about in this article...  
&nbsp;&nbsp;&nbsp;[http://www.ddj.com/dept/architect/199902669](http://www.ddj.com/dept/architect/199902669)  
when using the 'thread.rb' Queue class.

I hacked around it by creating a Queue of Arrays, but that probably  
creates more garbage than I should.

This "Spin Buffer" trick looks Good...  
&nbsp;&nbsp;&nbsp;[http://www.ddj.com/dept/architect/199902669?pgno=2](http://www.ddj.com/dept/architect/199902669?pgno=2)

Anyone have a ruby Spin Buffer implementation lying around?

John Carter Phone : (64)(3) 358 6639  
Tait Electronics Fax : (64)(3) 359 4632  
PO Box 1645 Christchurch Email : john.carter@tait.co.nz  
New Zealand

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [16 July 2007 05:30 UTC](https://rubytalk.org/t/spin-buffers/39138/2 "2007-07-16T05:30:23Z")

</div>

> Hmm. Just being reading the Dr. Dobbs.
> 
> I certainly have hit the bottleneck talked about in this article...  
> &nbsp;&nbsp;[http://www.ddj.com/dept/architect/199902669](http://www.ddj.com/dept/architect/199902669)  
> when using the 'thread.rb' Queue class.

What exactly makes you believe that? Can you show some code and / or figures that back this theory?

> I hacked around it by creating a Queue of Arrays, but that probably  
> creates more garbage than I should.

Difficult to say without seeing the code. Generally I'd say that Queue is pretty efficient already since it's implemented in C AFAIR.

> This "Spin Buffer" trick looks Good...  
> &nbsp;&nbsp;[Spin Buffers | Dr Dobb's](http://www.ddj.com/dept/architect/199902669?pgno=2)
> 
> Anyone have a ruby Spin Buffer implementation lying around?

I'd check with the RAA.

Kind regards

&nbsp;&nbsp;robert

> **···**
>
> On 16.07.2007 04:20, John Carter wrote:

---

<div class="post-metadata">

**Author:** ![a11](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/a11/32/8169_2.png) [@a11](https://rubytalk.org/u/a11)\
**Post date:** [16 July 2007 05:46 UTC](https://rubytalk.org/t/spin-buffers/39138/3 "2007-07-16T05:46:14Z")

</div>

no, but i'd be inclined to try writing one on top of guy's mmap ext - the interface is that of string so the example should map (no pun intended) rather well.

cheers.

a @ [http://drawohara.com/](http://drawohara.com/)

> **···**
>
> On Jul 15, 2007, at 8:20 PM, John Carter wrote:
> 
> > Anyone have a ruby Spin Buffer implementation lying around?
> 
> --  
> we can deny everything, except that we have the possibility of being better. simply reflect on that.  
> h.h. the 14th dalai lama

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [18 July 2007 00:56 UTC](https://rubytalk.org/t/spin-buffers/39138/4 "2007-07-18T00:56:57Z")

</div>

> What exactly makes you believe that? Can you show some code and / or  
> figures that back this theory?

Seconded. Measure first, then optimize.

> \> I hacked around it by creating a Queue of Arrays, but that probably  
> \> creates more garbage than I should.

That probably performs slower than Queue.

> Difficult to say without seeing the code. Generally I'd say that Queue  
> is pretty efficient already since it's implemented in C AFAIR.

Depends on the version of Ruby. It certainly is if you're using  
fastthread. If he's not using fastthread, I'd recommend giving it a  
try.

> \> This "Spin Buffer" trick looks Good...  
> \> [http://www.ddj.com/dept/architect/199902669?pgno=2](http://www.ddj.com/dept/architect/199902669?pgno=2)  
> \>  
> \> Anyone have a ruby Spin Buffer implementation lying around?

"Spin Buffers" are \_snake oil\_; they get their "speed" at the expense of  
correctness -- the implementation given in the DDJ article is not  
threadsafe. If it were rewritten to be threadsafe, it would actually be  
slower than some simpler alternatives.

-mental

> **···**
>
> On Mon, 2007-07-16 at 14:30 +0900, Robert Klemme wrote:

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [18 July 2007 00:58 UTC](https://rubytalk.org/t/spin-buffers/39138/5 "2007-07-18T00:58:59Z")

</div>

What does mmap have to do with communication between Ruby threads?

(and again, I'd like to emphasize that "spin buffers" are snake oil)

-mental

> **···**
>
> On Mon, 2007-07-16 at 14:46 +0900, ara.t.howard wrote:
> 
> > no, but i'd be inclined to try writing one on top of guy's mmap ext -  
> > the interface is that of string so the example should map (no pun  
> > intended) rather well.

---

<div class="post-metadata">

**Author:** ![John\_Carter](https://avatars.discourse-cdn.com/v4/letter/j/2bfe46/32.png) [@John\_Carter](https://rubytalk.org/u/John_Carter)\
**Post date:** [18 July 2007 01:32 UTC](https://rubytalk.org/t/spin-buffers/39138/6 "2007-07-18T01:32:10Z")

</div>

And yes... I did, as always, measure before I optimized and my Queue  
of Array trick did speed things measurably.

> Depends on the version of Ruby. It certainly is if you're using  
> fastthread. If he's not using fastthread, I'd recommend giving it a  
> try.

I'm not using fastthread since it caused code that had been working  
fine for several years to curl up and die. So I disabled it.

I'll admit I never got to the bottom of why it did.... (and no, it  
wasn't the code that used my queue of arrays trick)

> > > This "Spin Buffer" trick looks Good...  
> > > &nbsp;&nbsp;[http://www.ddj.com/dept/architect/199902669?pgno=2](http://www.ddj.com/dept/architect/199902669?pgno=2)
> > > 
> > > Anyone have a ruby Spin Buffer implementation lying around?

> "Spin Buffers" are \_snake oil\_; they get their "speed" at the expense of  
> correctness -- the implementation given in the DDJ article is not  
> threadsafe.

Well that was a bit of a problem with the article... it didn't  
actually include the code so I can't say one way or the other on  
that. Any pointers as to what the incorrect bit is?

John Carter Phone : (64)(3) 358 6639  
Tait Electronics Fax : (64)(3) 359 4632  
PO Box 1645 Christchurch Email : john.carter@tait.co.nz  
New Zealand

> **···**
>
> On Wed, 18 Jul 2007, MenTaLguY wrote:

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [18 July 2007 02:29 UTC](https://rubytalk.org/t/spin-buffers/39138/7 "2007-07-18T02:29:11Z")

</div>

> And yes... I did, as always, measure before I optimized and my Queue  
> of Array trick did speed things measurably.

Hmm, did you just mean sending batches of objects as arrays, rather than  
sending individual objects? That would make sense and it's a reasonable  
optimization, provided you're careful about not touching the array on  
the sending side once it's been added to the queue. I'd just finished  
reading the DDJ article and was imagining something more elaborate at  
first...

> \> Depends on the version of Ruby. It certainly is if you're using  
> \> fastthread. If he's not using fastthread, I'd recommend giving it a  
> \> try.
> 
> I'm not using fastthread since it caused code that had been working  
> fine for several years to curl up and die. So I disabled it.

It might be worth looking into why -- if it doesn't work with  
fastthread, it's unlikely to work with future versions of Ruby  
(including 1.8.6 or later) or alternate Ruby implementations like JRuby.

Absent fastthread bugs (which do crop up occasionally, though rarely at  
this point), there are two main sources of problems:

1. Code that tries to manipulate the internal implementation of  
thread.rb objects (Mutex, ConditionVariable, Queue, etc); not always a  
bug, but it isn't portable or future-proof.

2. Code which has existing concurrency bugs which show up more clearly  
when the scheduling behavior changes.

> \> "Spin Buffers" are \_snake oil\_; they get their "speed" at the expense of  
> \> correctness -- the implementation given in the DDJ article is not  
> \> threadsafe.
> 
> Well that was a bit of a problem with the article... it didn't  
> actually include the code so I can't say one way or the other on  
> that. Any pointers as to what the incorrect bit is?

The code is included in the source archive on the DDJ ftp site as  
spin.txt (and spin.zip, which has his test harness):

ftp://66.77.27.238/sourcecode/ddj/2007/0707.zip

It's not just a one-line bug, but a systemic problem: the author assumes  
that the only reason he needs synchronization is to prevent two threads  
from modifying the same data at the same time (hence the elaborate dance  
with the buffers); in reality, however, it's also important to protect  
the code from compiler (and CPU) optimizations which will alter its  
behavior in undesirable ways if it is used in a multi-threaded context  
(e.g. it becomes possible for the reader to see the writer's addition of  
the object but see the object in an uninitalized state!). He's  
basically trying to get a performance "free lunch" by not using  
synchronization.

Concurrency bugs are notoriously hard to find through testing, and it  
doesn't help that the author only ever tested on hardware which is  
extremely forgiving about concurrency (a single hyperthreaded x86 CPU).  
It also didn't help that all his test did was count how many objects  
were read from the queue.

-mental

> **···**
>
> On Wed, 2007-07-18 at 10:32 +0900, John Carter wrote:

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [18 July 2007 02:43 UTC](https://rubytalk.org/t/spin-buffers/39138/8 "2007-07-18T02:43:11Z")

</div>

At any rate, I think your best option is something like fastthread's  
Queue. It shouldn't be too hard to change the code to work with it, and  
it's possible that you've uncovered a bug in that "working" code which  
really needs to be fixed.

-mental

> **···**
>
> On Wed, 2007-07-18 at 10:32 +0900, John Carter wrote:
> 
> > I'm not using fastthread since it caused code that had been working  
> > fine for several years to curl up and die. So I disabled it.

---

<div class="post-metadata">

**Author:** ![MenTaLguY1](https://avatars.discourse-cdn.com/v4/letter/m/97f17d/32.png) [@MenTaLguY1](https://rubytalk.org/u/MenTaLguY1)\
**Post date:** [18 July 2007 02:54 UTC](https://rubytalk.org/t/spin-buffers/39138/9 "2007-07-18T02:54:52Z")

</div>

It is worth noting that these are not issues if you're only writing for  
Ruby 1.8, which has neither an optimizing compiler nor native threads  
(where instruction ordering and cache effects become a consideration).

So, does that mean a Spin Buffer implementation would theoretically be  
okay for Ruby 1.8? Maybe as far as those issues go. But note that the  
author himself identifies a number of issues with spin buffers when the  
readers and writers get out of sync, including poor performance and the  
reader getting "stuck" on a non-empty buffer if it hits a buffer  
boundary when no writers are writing. Those are actually inherent to  
the data structure's design.

-mental

> **···**
>
> On Wed, 2007-07-18 at 11:29 +0900, MenTaLguY wrote:
> 
> > in reality, however, it's also important to protect  
> > the code from compiler (and CPU) optimizations which will alter its  
> > behavior in undesirable ways if it is used in a multi-threaded context  
> > (e.g. it becomes possible for the reader to see the writer's addition of  
> > the object but see the object in an uninitalized state!).
