<br><br><div class="gmail_quote">On Mon, Dec 7, 2009 at 1:08 PM, Eli Barzilay <span dir="ltr"><<a href="mailto:eli@barzilay.org">eli@barzilay.org</a>></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>
> I'm pleased to announce the initial release of parallel futures, a<br>
> construct for fine-grained parallelism in PLT.<br>
<br>
</div>Random notes:<br>
<br>
1. Your message mentioned requiring `scheme/futures' -- it should be<br>
`scheme/future'. </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' 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'.<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'm not sure why you would need a separate function for <br>
futures-count, unless you'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'<br>
and `--disable-mred' 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's<br>
"not use futures", since on windows there is no configure step.<br>
<br>
5. The term `unsafe' 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' 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 "unsafe primitives"... A question about the confusion<br>
with `scheme/unsafe/ops' or `scheme/foreign' would also be<br>
difficult to answer when the only term you have is "unsafe".)<br></blockquote><div><br>Good point - perhaps it'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't make much sense.)<br>
<br>
7. There should be some way to disable futures. I'm thinking of<br>
situations like running sandboxed code, where you don'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'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'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'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'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 "unsafe" primitives make some sense as far as using them.<br>
(For example, it'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) '(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'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) '(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'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 '(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'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 '(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 "safe", and you get<br>
the usual races -- so the three cores that use the second counter<br>
keep running into races of "read N, write N+1 after another thread<br>
wrote N+1 or more", resulting in races mostly making the counts<br>
the same, but with some "success rate" 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 "unsafe"), 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 "very" independent tasks.<br></blockquote><div><br>An excellent point - I'll update the documentation to include something to this effect. We've had several discussions about adding concurrency primitives <br>
with futures - but you're right, as of now you're restricted to independent tasks because there really isn'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>