<br><br><div class="gmail_quote">On Mon, Dec 7, 2009 at 1:08 PM, Eli Barzilay <span dir="ltr">&lt;<a href="mailto:eli@barzilay.org">eli@barzilay.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">On Dec  7, James Swaine wrote:<br>
&gt; I&#39;m pleased to announce the initial release of parallel futures, a<br>
&gt; construct for fine-grained parallelism in PLT.<br>
<br>
</div>Random notes:<br>
<br>
1. Your message mentioned requiring `scheme/futures&#39; -- it should be<br>
   `scheme/future&#39;. </blockquote><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
2. Is it possible to move `processor-count&#39; into the core and make it<br>
   available for non-future builds too?  That function is useful even<br>
   without futures (for example, for code that runs subprocesses for<br>
   all cores -- in my scripts I just read a from from /proc, and<br>
   having a portable replacement would be nice).  For the sake of code<br>
   that wants to use futures, I think that the current function is<br>
   better named `futures-count&#39;.<br></blockquote><div><br>This sounds fine to me.  processor-count should always have the same behavior, regardless <br>of whether futures are enabled.  But I&#39;m not sure why you would need a separate function for <br>
futures-count, unless you&#39;re intending it to be related to question (6) below?<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<br>
3. Can you please include the command line for building with futures<br>
   support?  This way, you can have it show both `--enable-futures&#39;<br>
   and `--disable-mred&#39; to avoid confusion.<br></blockquote><div><br>Yes, will do.<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<br>
4. You should also mention what Windows users should do, even if it&#39;s<br>
   &quot;not use futures&quot;, since on windows there is no configure step.<br>
<br>
5. The term `unsafe&#39; was used with a particular meaning by the foreign<br>
   interface, then came the scheme/unsafe/ops library with a slightly<br>
   different but related meaning.  The futures documentation uses<br>
   `unsafe&#39; with a completely different meaning -- so it would be<br>
   better to find some other term, or at least make that very clear.<br>
   (This applies in general too -- for example, in your reply to Jay<br>
   you mention &quot;unsafe primitives&quot;...  A question about the confusion<br>
   with `scheme/unsafe/ops&#39; or `scheme/foreign&#39; would also be<br>
   difficult to answer when the only term you have is &quot;unsafe&quot;.)<br></blockquote><div><br>Good point - perhaps it&#39;d be best to use other terminology to avoid confusion here.<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<br>
6. It would be nice to be able to get a list of the currently running<br>
   futures?  (With threads, this is possible through custodians --<br>
   with futures being global this won&#39;t make much sense.)<br>
<br>
7. There should be some way to disable futures.  I&#39;m thinking of<br>
   situations like running sandboxed code, where you don&#39;t want<br>
   untrusted code to be able to grab cpus.  Of course it would be nice<br>
   to be able to have a finer control over it (like how many cores<br>
   each future sees) -- but with nested futures being forbidden there<br>
   doesn&#39;t seem to be much point in that.<br>
<br>
8. Looks like there is no way to kill a running future.  There should<br>
   be one.  To make it practical, it should also be killed on a<br>
   custodian shutdown -- but again, it&#39;s not clear to me how that<br>
   might look when futures are inherently global to the process.<br>
<br>
9. Worse, it looks like when a future is touched, it&#39;s not really<br>
   joining the main execution thread.  For example, when I run your<br>
   suggested example:<br>
<div class="im"><br>
     (for-each touch<br>
               (for/list ([i (in-range 0 (processor-count))])<br>
                 (future loop)))<br>
<br>
</div>   I get my 4 cores spinning away happily, but hitting break leaves<br>
   them *all* running.  I&#39;d expect the first future to stop as a<br>
   result.  And with future values giving you only the ability to<br>
   touch, this means that your example is a way to render your<br>
   mzscheme process useless until it exits.<br>
<br>
10. (This will be a long one.)<br>
<br>
    The &quot;unsafe&quot; primitives make some sense as far as using them.<br>
    (For example, it&#39;s clear that using any IO will suspend the<br>
    future.)<br>
<br>
    But there is no mention at all of what happens when there are<br>
    potential race conditions.  Is writing to memory going to block a<br>
    future in any way?  How is reading handled?  Since this is not<br>
    documented, I ran some experiments.  (My machine has two double<br>
    core Xeons cpus at 3ghz, in case it matters.)<br>
<br>
    First, I did this:<br>
<br>
      #lang scheme<br>
      (require scheme/future)<br>
      (define x<br>
        (let ([v (vector 0 0 0 0)])<br>
          (define ((spin n))<br>
            (let loop () (vector-set! v n (add1 (vector-ref v n))) (loop)))<br>
          (cons v (map (compose future spin) &#39;(0 1 2 3)))))<br>
      (sleep 10)<br>
      x<br>
      (exit)<br>
<br>
    and the printout had similar numbers, between 53M and 58M.<br>
    Realizing that there&#39;s nothing useful I can do with the future<br>
    values, I changed it to:<br>
<br>
      (define x<br>
        (let ([v (vector 0 0 0 0)])<br>
          (define ((spin n))<br>
            (let loop () (vector-set! v n (add1 (vector-ref v n))) (loop)))<br>
          (for-each (compose future spin) &#39;(0 1 2 3))<br>
          v))<br>
<br>
    and this produced very different numbers, with one counter being<br>
    at around 110M, two more around 50-60M, and one around 10M.  The<br>
    high one was usually the first, and the low one was usually the<br>
    last.  I couldn&#39;t really attribute this to delays in firing off<br>
    the futures, because one of the results was #(74M 49M 98M 10M).<br>
    Next I tried to rephrase it, to avoid delays in starting them as<br>
    soon as possible:<br>
<br>
      (define x<br>
        (let ([v (vector 0 0 0 0)])<br>
          (define (spin n)<br>
            (future<br>
             (lambda ()<br>
               (let loop () (vector-set! v n (add1 (vector-ref v n))) (loop)))))<br>
          (for-each spin &#39;(0 1 2 3))<br>
          v))<br>
<br>
    and the results went back to all being around 60M.  The *sum* of<br>
    all counters is roughly the same (around 230M), but I can&#39;t think<br>
    of any way the previous example would have such huge differences.<br>
<br>
    Next, I tried this:<br>
<br>
      (define x<br>
        (let ([v (vector 0 0)])<br>
          (define (spin n)<br>
            (future<br>
             (lambda ()<br>
               (let loop () (vector-set! v n (add1 (vector-ref v n))) (loop)))))<br>
          (for-each spin &#39;(0 1 1 1))<br>
          v))<br>
<br>
    and the counts were 63M and 77M resp.  This *looks* like reading<br>
    and writing from the same memory location is &quot;safe&quot;, and you get<br>
    the usual races -- so the three cores that use the second counter<br>
    keep running into races of &quot;read N, write N+1 after another thread<br>
    wrote N+1 or more&quot;, resulting in races mostly making the counts<br>
    the same, but with some &quot;success rate&quot; that leads to a higher<br>
    number.<br>
<br>
    If this is correct, and together with the fact that the usual<br>
    synchronization primitives in mzscheme are useless in futures<br>
    (since they seem to be &quot;unsafe&quot;), then this is a pretty important<br>
    thing to describe in the docs.  Without being able to sync, then<br>
    people should be told very explicitly that the system avoids race<br>
    conditions that violate the mzscheme vm, but it knows nothing<br>
    about your own races, which means that you should be extra careful<br>
    to use futures for &quot;very&quot; independent tasks.<br></blockquote><div><br>An excellent point - I&#39;ll update the documentation to include something to this effect.  We&#39;ve had several discussions about adding concurrency primitives <br>
with futures - but you&#39;re right, as of now you&#39;re restricted to independent tasks because there really isn&#39;t an effective way to <br>do inter-thread communication.<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<font color="#888888"><br>
--<br>
          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:<br>
                    <a href="http://barzilay.org/" target="_blank">http://barzilay.org/</a>                   Maze is Life!<br>
</font></blockquote></div><br>