<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en">
<head>
  <title>the all-thing</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link rel="stylesheet" href="/static/style.css" type="text/css" />
  <link rel="alternate" type="application/rss+xml" title="the all-thing RSS feed" href="/index.rss" />
  <link rel="alternate" type="text/plain" title="the all-thing in plain text" href="/index.txt" />
  <script type="text/javascript" src="/static/mootools.js"></script>
  <script type="text/javascript" src="http://music.masanjin.net:9292/waxiest.js"></script>
</head>
<body>

<div id="main">
  <div id="header">
    <h1><a  href="/">the all-thing</a></h1>
    
  </div>
  <div id="sidebar">
    <h3>Recent comments</h3>

    <ul class="sidebar-list">
    
    <li><b><a  href="/whisper-0.5#58174069c046a78e55f02ef81da81e74">Dominique Julia</a></b>
        <i><a  href="/whisper-0.5">Whisper 0.5 released</a></i>
           one week ago
    </li>
    
    <li><b><a  href="/ruby-ncurses-and-thread-blocking#8fa2a0f392d7c0562d630e4936407c11">William Morgan</a></b>
        <i><a  href="/ruby-ncurses-and-thread-blocking">Ruby, Ncurses and blocked threads</a></i>
           three months ago
    </li>
    
    <li><b><a  href="/git-wtf-bf06ab7-released#533654a7a229569e27a6d0afd716c444">William Morgan</a></b>
        <i><a  href="/git-wtf-bf06ab7-released">git wtf bf06ab7 released</a></i>
           three months ago
    </li>
    
    <li><b><a  href="/git-wtf-bf06ab7-released#b7b7a905477674eb6985b34a964a0dca">Joao Nelas</a></b>
        <i><a  href="/git-wtf-bf06ab7-released">git wtf bf06ab7 released</a></i>
           three months ago
    </li>
    
    <li><b><a  href="/ruby-ncurses-and-thread-blocking#b00001114360ac152f87d4ac2a6e0c5b">Ollivier Robert</a></b>
        <i><a  href="/ruby-ncurses-and-thread-blocking">Ruby, Ncurses and blocked threads</a></i>
           three months ago
    </li>
    
    </ul>

    <h3>Authors</h3>
    <ul class="sidebar-list">
    
      <li><a class="author" href="/by/William+Morgan/">William&nbsp;Morgan</a>&nbsp;(65) </li>
    
    </ul>

    <h3>Tags</h3>
    <ul class="sidebar-list">
    
      <li><a class="label" href="/label/releases/">releases</a>&nbsp;(15) </li>
    
      <li><a class="label" href="/label/whisper/">whisper</a>&nbsp;(13) </li>
    
      <li><a class="label" href="/label/git/">git</a>&nbsp;(9) </li>
    
      <li><a class="label" href="/label/stats/">stats</a>&nbsp;(8) </li>
    
      <li><a class="label" href="/label/trollop/">trollop</a>&nbsp;(6) </li>
    
      <li><a class="label" href="/label/ruby/">ruby</a>&nbsp;(6) </li>
    
      <li><a class="label" href="/label/sup/">sup</a>&nbsp;(6) </li>
    
      <li><a class="label" href="/label/git-wtf/">git-wtf</a>&nbsp;(4) </li>
    
      <li><a class="label" href="/label/vm/">vm</a>&nbsp;(4) </li>
    
      <li><a class="label" href="/label/mathml/">mathml</a>&nbsp;(3) </li>
    
      <li><a class="label" href="/label/continuations/">continuations</a>&nbsp;(3) </li>
    
      <li><a class="label" href="/label/ditz/">ditz</a>&nbsp;(3) </li>
    
      <li><a class="label" href="/label/proglang/">proglang</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/optimization/">optimization</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/benchmarks/">benchmarks</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/rubinius/">rubinius</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/inlining/">inlining</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/ubuntu/">ubuntu</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/fibers/">fibers</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/ritex/">ritex</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/ruby1.9/">ruby1.9</a>&nbsp;(2) </li>
    
      <li><a class="label" href="/label/ncurses/">ncurses</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/javascript/">javascript</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/media/">media</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/vim/">vim</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/classification/">classification</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/massachusetts/">massachusetts</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/greasemonkey/">greasemonkey</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/wine/">wine</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/readme/">readme</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/ancient-greek/">ancient-greek</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/web/">web</a>&nbsp;(1) </li>
    
      <li><a class="label" href="/label/current+events/">current&nbsp;events</a>&nbsp;(1) </li>
    
    </ul>

    <h3>Other formats</h3>
    <ul class="sidebar-list">
    <li><a href="/index.rss"><img src="/static/rss-badge.png"/></a></li>
    <li><a href="/index.txt">plain text version</a></li>
    </ul>

    <h3 class="waxiest.author.original">Who is this man?</h3>
    <h3 class="waxiest.author.beautiful" style="display:none">I must find out more about this beautiful creature</h3>
    <h3 class="waxiest.author.beautifulbig" style="display:none">I MUST FIND OUT MORE ABOUT THIS BEAUTIFUL CREATURE</h3>
    <h3 class="waxiest.author.originalbig" style="display:none">WHO IS THIS MAN?</h3>

    <script type="text/javascript">
      var w = waxiest();
      w.optimizeHTMLSection("author", ["original", "beautiful", "beautifulbig", "originalbig"]);
    </script>

    <a href="http://masanjin.net" onClick="w.goalReached('greeting')">William Morgan</a>
  </div>
  <div id="content">
    <h2><a  href="/fibers-via-continuations">Fibers via Continuations</a></h2>

<div class="byline">
  <a  href="/by/William+Morgan/">William Morgan</a>,
  <span title="9 months ago">June  1, 2009  2:47pm</span>
</div>

  <div class="labels"><span class='label'><a  href="/label/ruby/">ruby</a></span> <span class='label'><a  href="/label/ruby1.9/">ruby1.9</a></span> <span class='label'><a  href="/label/fibers/">fibers</a></span> <span class='label'><a  href="/label/continuations/">continuations</a></span> </div>


<p class='first'>In the last post I talked about some <a href="http://all-thing.net/fibers">differences between fibers and
continuations</a>. What may not have been clear is
that continuations are more primitive and flexible than fibers are. In fact,
you can implement fibers using continuations.</p>
<p>Here&#8217;s how. The basic idea is that we want to maintain two variables with
continuations in them, <code>inside</code> and <code>outside</code>. The first one will transfer
execution into the block of code that forms the fiber. The second will transfer
control back to the outside world.</p>
<p>When the outside world calls <code>#resume</code>, we save our continuation point as
<code>outside</code>, and call the current <code>inside</code> continuation. When, within the block,
<code>#yield</code> is called, we save our current continuation point as <code>inside</code>, and
transfer code back to the current <code>outside</code>.</p>
<p>There are a few more details in terms of passing values from <code>#yield</code> to
<code>#resume</code>, handling the return value of the block, and handling excessive
calls to #<code>resume</code>, but that&#8217;s the basic story. Here&#8217;s the code:
<code><pre class="ruby"><span class="ident">require</span> <span class="punct">'</span><span class="string">continuation</span><span class="punct">'</span>

<span class="keyword">class </span><span class="class">CFiber</span>
  <span class="keyword">class </span><span class="class">Error</span> <span class="punct">&lt;</span> <span class="constant">StandardError</span><span class="punct">;</span> <span class="keyword">end</span>

  <span class="keyword">def </span><span class="method">initialize</span> <span class="punct">&amp;</span><span class="ident">block</span>
    <span class="attribute">@block</span> <span class="punct">=</span> <span class="ident">block</span>
    <span class="ident">callcc</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">cc</span><span class="punct">|</span>
      <span class="attribute">@inside</span> <span class="punct">=</span> <span class="ident">cc</span>
      <span class="keyword">return</span>
    <span class="keyword">end</span>
    <span class="attribute">@var</span> <span class="punct">=</span> <span class="attribute">@block</span><span class="punct">.</span><span class="ident">call</span> <span class="constant">self</span>
    <span class="attribute">@inside</span> <span class="punct">=</span> <span class="constant">nil</span>
    <span class="attribute">@outside</span><span class="punct">.</span><span class="ident">call</span>
  <span class="keyword">end</span>

  <span class="keyword">def </span><span class="method">resume</span>
    <span class="keyword">raise</span> <span class="constant">Error</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">dead cfiber called!</span><span class="punct">&quot;</span> <span class="keyword">unless</span> <span class="attribute">@inside</span>
    <span class="ident">callcc</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">cc</span><span class="punct">|</span>
      <span class="attribute">@outside</span> <span class="punct">=</span> <span class="ident">cc</span>
      <span class="attribute">@inside</span><span class="punct">.</span><span class="ident">call</span>
    <span class="keyword">end</span>
    <span class="attribute">@var</span>
  <span class="keyword">end</span>

  <span class="keyword">def </span><span class="method">yield</span> <span class="ident">var</span>
    <span class="ident">callcc</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">cc</span><span class="punct">|</span>
      <span class="attribute">@var</span> <span class="punct">=</span> <span class="ident">var</span>
      <span class="attribute">@inside</span> <span class="punct">=</span> <span class="ident">cc</span>
      <span class="attribute">@outside</span><span class="punct">.</span><span class="ident">call</span>
    <span class="keyword">end</span>
  <span class="keyword">end</span>
<span class="keyword">end</span></pre></code></p>
<p>This is also runnable on Ruby 1.8&#8212;just remove the <code>require</code>.</p>
<p>So why does Ruby 1.9 bother to implement fibers, when we can just use
continuations?  I don&#8217;t know what the real answer is, but &#8220;speed&#8221; is at least a
<em>good</em> answer. Let&#8217;s do some some benchmarking to compare the two:</p>
<p><code><pre class="ruby"><span class="ident">require</span> <span class="punct">'</span><span class="string">benchmark</span><span class="punct">'</span>
<span class="ident">n</span> <span class="punct">=</span> <span class="constant">ARGV</span><span class="punct">.</span><span class="ident">shift</span><span class="punct">.</span><span class="ident">to_i</span>
<span class="constant">Benchmark</span><span class="punct">.</span><span class="ident">bm</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">bm</span><span class="punct">|</span>
  <span class="ident">bm</span><span class="punct">.</span><span class="ident">report</span> <span class="punct">&quot;</span><span class="string"> fibers</span><span class="punct">&quot;</span> <span class="keyword">do</span>
    <span class="ident">f</span> <span class="punct">=</span> <span class="constant">Fiber</span><span class="punct">.</span><span class="ident">new</span> <span class="keyword">do</span>
      <span class="ident">x</span><span class="punct">,</span> <span class="ident">y</span> <span class="punct">=</span> <span class="number">0</span><span class="punct">,</span> <span class="number">1</span>
      <span class="ident">loop</span> <span class="keyword">do</span>
        <span class="constant">Fiber</span><span class="punct">.</span><span class="ident">yield</span> <span class="ident">y</span>
        <span class="ident">x</span><span class="punct">,</span> <span class="ident">y</span> <span class="punct">=</span> <span class="ident">y</span><span class="punct">,</span> <span class="ident">x</span> <span class="punct">+</span> <span class="ident">y</span>
      <span class="keyword">end</span>
    <span class="keyword">end</span>

    <span class="ident">n</span><span class="punct">.</span><span class="ident">times</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">i</span><span class="punct">|</span> <span class="ident">f</span><span class="punct">.</span><span class="ident">resume</span> <span class="punct">}</span>
  <span class="keyword">end</span>

  <span class="ident">bm</span><span class="punct">.</span><span class="ident">report</span> <span class="punct">&quot;</span><span class="string">cfibers</span><span class="punct">&quot;</span> <span class="keyword">do</span>
    <span class="ident">f</span> <span class="punct">=</span> <span class="constant">CFiber</span><span class="punct">.</span><span class="ident">new</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">c</span><span class="punct">|</span>
      <span class="ident">x</span><span class="punct">,</span> <span class="ident">y</span> <span class="punct">=</span> <span class="number">0</span><span class="punct">,</span> <span class="number">1</span>
      <span class="ident">loop</span> <span class="keyword">do</span>
        <span class="ident">c</span><span class="punct">.</span><span class="ident">yield</span> <span class="ident">y</span>
        <span class="ident">x</span><span class="punct">,</span> <span class="ident">y</span> <span class="punct">=</span> <span class="ident">y</span><span class="punct">,</span> <span class="ident">x</span> <span class="punct">+</span> <span class="ident">y</span>
      <span class="keyword">end</span>
    <span class="keyword">end</span>

    <span class="ident">n</span><span class="punct">.</span><span class="ident">times</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">i</span><span class="punct">|</span> <span class="ident">f</span><span class="punct">.</span><span class="ident">resume</span> <span class="punct">}</span>
  <span class="keyword">end</span>
<span class="keyword">end</span></pre></code></p>
<p>We&#8217;ll start with backporting that code to the Ruby 1.8.7 that Ubuntu provides
(ruby 1.8.7 (2008-08-11 patchlevel 72)). For 10000 Fibonacci numbers, we see:</p>
<table style="margin-left: auto; margin-right: auto;">
	<tr>
		<td>         </td>
		<th>user   </th>
		<th>system </th>
		<th>total  </th>
		<th>real   </th>
	</tr>
	<tr>
		<td> <em>cfibers</em> </td>
		<td style="text-align:right;">0.810000 </td>
		<td style="text-align:right;">0.070000 </td>
		<td style="text-align:right;">0.880000 </td>
		<td style="text-align:right;">0.879930 </td>
	</tr>
</table>
<p>That&#8217;s roughly 11.4kfps (that&#8217;s thousand Fibonacci numbers per second) that we
can produce using continuation-based fibers.</p>
<p>Let&#8217;s try the ancient Ruby 1.9.0 that Ubuntu provides (Ruby 1.9.0 (2008-06-20
revision 17482)):</p>
<table style="margin-left: auto; margin-right: auto;">
	<tr>
		<td>         </td>
		<th>user   </th>
		<th>system </th>
		<th>total  </th>
		<th>real    </th>
	</tr>
	<tr>
		<td> <em>fibers</em> </td>
		<td style="text-align:right;">0.040000 </td>
		<td style="text-align:right;">0.000000 </td>
		<td style="text-align:right;">0.040000 </td>
		<td style="text-align:right;">0.037583 </td>
	</tr>
	<tr>
		<td> <em>cfibers</em> </td>
		<td style="text-align:right;">18.680000 </td>
		<td style="text-align:right;">1.770000 </td>
		<td style="text-align:right;">20.450000 </td>
		<td style="text-align:right;">20.482006 </td>
	</tr>
</table>
<p>Wow, fibers are fast: 250kfps. But things have gotten significantly worse for
cfibers, clocking at a measely 0.489kfps for cfibers.</p>
<p>Finally let&#8217;s try the latest and greatest Ruby 1.9.1 (ruby 1.9.1p129
(2009-05-12 revision 23412)):</p>
<table style="margin-left: auto; margin-right: auto;">
	<tr>
		<td>         </td>
		<th>user   </th>
		<th>system </th>
		<th>total  </th>
		<th>real    </th>
	</tr>
	<tr>
		<td> <em>fibers</em>  </td>
		<td style="text-align:right;">0.040000 </td>
		<td style="text-align:right;">0.000000 </td>
		<td style="text-align:right;">0.040000 </td>
		<td style="text-align:right;">0.035148 </td>
	</tr>
	<tr>
		<td> <em>cfibers</em> </td>
		<td style="text-align:right;">0.150000 </td>
		<td style="text-align:right;">0.000000 </td>
		<td style="text-align:right;">0.150000 </td>
		<td style="text-align:right;">0.155890 </td>
	</tr>
</table>
<p>Fibers are just as fast as before, but continuations have improved
dramatically&#8212;from 11.4kfps to 66.6kfps. Still, native fibers are more than
three times faster.</p>
<p>So perhaps Ruby 1.9.1 is the best of both worlds. When you need fast
non-preemptive concurrency, you can use native fibers; when you need to
implement your own crazy control structures, you can use continuations and be
assured that they&#8217;re still pretty darn fast (at least, as far as Ruby
operations are concerned).</p>

<h4>Discussion</h4>
<a name="comments"></a>

<ul class="comment-tree">

  
  
</ul>

<p class="comment-instructions">To leave a new comment, enter your email
address. A copy of the article will be sent to you via email.</p>
<form id='comment-form-fibers-via-continuations' action='/comment/fibers-via-continuations' method='post' class='comment-form'>
  <input type='text' name='email' id='textfield-email'/>
  <input type='submit' value='email me' id='submit-email me'/>
  <span class="form-result" id="form-result-fibers-via-continuations"><!-- spanna --></span>
</form>


<script type="text/javascript">
/* <![CDATA[ */
$$('.comment-form').addEvent('submit', function(e) {
  e.stop();
  var el = this.getElement('.form-result');
  var result = el.empty().addClass('ajax-loading');
  this.set('send', {
    method: 'post',
    onComplete: function(response) { 
      result.removeClass('ajax-loading');
      result.set('html', response);
    },
  });
  this.send();
});
/* ]]> */
</script>


<script type="text/javascript">
/* <![CDATA[ */
$$('.reply-to-link').each(function(link, i) {
  var box = link.getParent().getParent().getElement('.reply-to-box');
  var oldHeight = box.getStyle("height");
  box.setStyle("height", 0);
  box.setStyle("opacity", 0);
  link.addEvent('click', function(e) {
    e.stop();
    box.setStyle("opacity", 1);
    box.setStyle("height", oldHeight);
    box.getElement("input").focus();
  });
});
/* ]]> */
</script>

  </div>

  <div id="footer" style="margin: 0px;">
    Served up by <a href="http://masanjin.net/whisper/">Whisper</a>. Yes!
  </div>
</div>
</body>
</html>
