Sophie

Sophie

distrib > Mandriva > 2010.0 > i586 > media > contrib-release > by-pkgid > bd5c3d824c3db63ffd9226c15941e6ad > files > 116

mozart-1.4.0-1mdv2010.0.i586.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>7 Concurrency For Free</TITLE><LINK href="ozdoc.css" rel="stylesheet" type="text/css"></HEAD><BODY><TABLE align="center" border="0" cellpadding="6" cellspacing="6" class="nav"><TR bgcolor="#DDDDDD"><TD><A href="node8.html">- Up -</A></TD><TD><A href="node10.html#chapter.concurrency.patterns">Next &gt;&gt;</A></TD></TR></TABLE><DIV id="chapter.concurrency.cheap"><H1><A name="chapter.concurrency.cheap">7 Concurrency For Free</A></H1><P>This part of the tutorial addresses the following theme: what happens to programming when support for concurrency is extremely cheap, economical, and efficient. Suddenly, an entirely different style of programming and design is made possible. We are going to explore and exploit this new freedom.</P><P>Oz has very efficient, very economical, very lightweight threads, with fair preemptive scheduling. We don't mean that Oz threads are just somewhat better than brand X; we mean that brand X can't even see our dust with a telescope, er... well, just about anyway! In order to assuage the skeptics, we first exhibit a program that demonstrates massive concurrency and exercises the worst case. Doubters are encouraged to throw that program at their favorite programming language... and watch it die, eventually. Meanwhile, you could mount a clay tablet device, and engage in the more rewarding exercise of installing Windows from sumerian backup.</P><P>The program is invoked with: </P><BLOCKQUOTE class="code"><CODE>death&nbsp;--threads&nbsp;</CODE><I>N</I><CODE>&nbsp;--times&nbsp;</CODE><I>M</I></BLOCKQUOTE><P> and creates <I>N</I> threads. Each thread does nothing but <EM>yield</EM> immediately. Normally we would let the preemptive scheduler take care of interrupting a thread to switch to a new one, but here, in order to exercise the worst case, as soon as a thread is allowed to run, it explicitly <EM>yields</EM>. Thus the program does little else but switch between threads. Each thread yields <I>M</I> times and then terminates. When all threads have terminated, the program also terminates.</P><P>I just tried the following: </P><BLOCKQUOTE class="code"><CODE>death&nbsp;--threads&nbsp;10000&nbsp;--times&nbsp;10</CODE></BLOCKQUOTE><P> In other words, 10000 threads are created and must each yield 10 times. This results in 100000 thread switches. It takes 3s on this little steam-driven laptop. I have run the same program on a real computer at the lab but using: </P><BLOCKQUOTE class="code"><CODE>death&nbsp;--threads&nbsp;100000&nbsp;--times&nbsp;10</CODE></BLOCKQUOTE><P> It takes 7.5s. There are 100000 threads at all time runnable, and they must perform 1000000 thread switches. Try creating 100000 threads in Java... really, go ahead, I insist! I promise not to laugh!</P><P>Just so you don't have to take my word for it, I coded the same program in Java and tried: </P><BLOCKQUOTE class="code"><CODE>java&nbsp;Death&nbsp;1000&nbsp;10</CODE></BLOCKQUOTE><P> This takes 2:40mn!</P><P>What was the point of this exercise? It was not prove that Oz is better than Java; in this respect the test above was deliberately unfair: Java was never intended to support designs with massive concurrency... and <EM>that</EM> is the point. Oz was from the start designed as a platform for concurrent computation. That concurrency is so cheap and efficient makes entirely new designs possible that would not be realistic or even conceivable in other languages. Whenever you need to perform an operation asynchronously you simply spawn a new thread. You can design your application as a collection of concurrent objects or agents, etc...</P><DIV class="unnumbered" id="death.in.oz"><H2><A name="death.in.oz">Death by Concurrency in Oz</A></H2><P>Here is the code of the Oz application used in the benchmark above: </P><BLOCKQUOTE><PRE><SPAN class="keyword">functor</SPAN>&nbsp;<BR><SPAN class="keyword">import</SPAN>&nbsp;Application<BR><SPAN class="keyword">define</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">Yield</SPAN>}&nbsp;{Thread<SPAN class="keyword">.</SPAN>preempt&nbsp;{Thread<SPAN class="keyword">.</SPAN>this}}&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">Run</SPAN>&nbsp;N}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Yield}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">if</SPAN>&nbsp;N<SPAN class="keyword">&gt;</SPAN>1&nbsp;<SPAN class="keyword">then</SPAN>&nbsp;{Run&nbsp;N<SPAN class="keyword">-</SPAN>1}&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;Args&nbsp;=&nbsp;{Application<SPAN class="keyword">.</SPAN>getCmdArgs<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;record(threads(single&nbsp;type:int&nbsp;optional:<SPAN class="keyword">false</SPAN>)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;times(&nbsp;&nbsp;single&nbsp;type:int&nbsp;optional:<SPAN class="keyword">false</SPAN>))}<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">proc</SPAN><SPAN class="variablename">&nbsp;</SPAN>{<SPAN class="functionname">Main</SPAN>&nbsp;N&nbsp;AllDone}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">if</SPAN>&nbsp;N<SPAN class="keyword">==</SPAN>0&nbsp;<SPAN class="keyword">then</SPAN>&nbsp;AllDone=<SPAN class="keyword">unit</SPAN>&nbsp;<SPAN class="keyword">else</SPAN>&nbsp;RestDone&nbsp;<SPAN class="keyword">in</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">thread</SPAN>&nbsp;{Run&nbsp;Args<SPAN class="keyword">.</SPAN>times}&nbsp;AllDone=RestDone&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{Main&nbsp;N<SPAN class="keyword">-</SPAN>1&nbsp;RestDone}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;<SPAN class="keyword">end</SPAN>&nbsp;<BR>&nbsp;&nbsp;&nbsp;{Wait&nbsp;{Main&nbsp;Args<SPAN class="keyword">.</SPAN>threads}}<BR>&nbsp;&nbsp;&nbsp;{Application<SPAN class="keyword">.</SPAN>exit&nbsp;0}<BR><SPAN class="keyword">end</SPAN>&nbsp;<BR></PRE></BLOCKQUOTE><P></P></DIV><DIV class="unnumbered"><H2><A name="label21">Death by Concurrency in Java</A></H2><P>Here is a very similar program, in Java: </P><BLOCKQUOTE><PRE><SPAN class="keyword">import</SPAN>&nbsp;<SPAN class="reference">java</SPAN>.<SPAN class="reference">lang</SPAN>.*;<BR><SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">MiniThread</SPAN>&nbsp;<SPAN class="keyword">extends</SPAN>&nbsp;<SPAN class="type">Thread</SPAN>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="type">int</SPAN>&nbsp;<SPAN class="variablename">n</SPAN>;<BR>&nbsp;&nbsp;&nbsp;&nbsp;MiniThread(<SPAN class="type">int</SPAN>&nbsp;<SPAN class="variablename">m</SPAN>)&nbsp;{&nbsp;n=m;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">public</SPAN>&nbsp;<SPAN class="type">void</SPAN>&nbsp;<SPAN class="functionname">run</SPAN>()&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">do</SPAN>&nbsp;{&nbsp;yield();&nbsp;n--;&nbsp;}&nbsp;<SPAN class="keyword">while</SPAN>&nbsp;(n&gt;0);<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}<BR><SPAN class="keyword">public</SPAN>&nbsp;<SPAN class="keyword">class</SPAN>&nbsp;<SPAN class="type">Death</SPAN>&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">public</SPAN>&nbsp;<SPAN class="keyword">static</SPAN>&nbsp;<SPAN class="type">void</SPAN>&nbsp;<SPAN class="functionname">main</SPAN>(<SPAN class="type">String</SPAN>[]&nbsp;<SPAN class="variablename">argv</SPAN>)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="type">int</SPAN>&nbsp;<SPAN class="variablename">threads</SPAN>&nbsp;=&nbsp;Integer.parseInt(argv[0]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="type">int</SPAN>&nbsp;<SPAN class="variablename">times</SPAN>&nbsp;&nbsp;&nbsp;=&nbsp;Integer.parseInt(argv[1]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="keyword">for</SPAN>(<SPAN class="type">int</SPAN>&nbsp;<SPAN class="variablename">i</SPAN>=threads;i&gt;0;i--)&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN class="type">MiniThread</SPAN>&nbsp;<SPAN class="variablename">t</SPAN>&nbsp;=&nbsp;<SPAN class="keyword">new</SPAN>&nbsp;<SPAN class="type">MiniThread</SPAN>(i);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.<SPAN class="type">start</SPAN>();<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}<BR></PRE></BLOCKQUOTE><P></P></DIV></DIV><TABLE align="center" border="0" cellpadding="6" cellspacing="6" class="nav"><TR bgcolor="#DDDDDD"><TD><A href="node8.html">- Up -</A></TD><TD><A href="node10.html#chapter.concurrency.patterns">Next &gt;&gt;</A></TD></TR></TABLE><HR><ADDRESS><A href="http://www.ps.uni-sb.de/~duchier/">Denys&nbsp;Duchier</A>, <A href="http://www.ps.uni-sb.de/~kornstae/">Leif&nbsp;Kornstaedt</A> and&nbsp;<A href="http://www.ps.uni-sb.de/~schulte/">Christian&nbsp;Schulte</A><BR><SPAN class="version">Version 1.4.0 (20090610)</SPAN></ADDRESS></BODY></HTML>