Re: [racket-users] Need help with parallelizing a procedure

2017-08-19 Thread Matthias Felleisen

May I recommend The Seasoned Schemer? 


> On Aug 19, 2017, at 9:28 AM, George Neuner  wrote:
> 
> 
> On 8/19/2017 6:16 AM, Zelphir Kaltstahl wrote:
>> I looked at the code for a while again and think I now begin to understand 
>> it a bit more:
>> 
>> I did not know `(let/ec` so I had to read about it. It says, that it is 
>> equivalent to `(call/ec proc` or something, which is equivalent to 
>> `(call-with-escape-continuation ...`. Uff … I don't know much about 
>> continuations, except from a vague idea of when they are called. The idea 
>> gets mingled with structures in other programming languages which are 
>> "catching exceptions" and such stuff. I don't know this stuff, so I guess 
>> `(call-with-escape-continuation` works like catching an exception, which is 
>> not really an exception, but just a signal, that code is returning. Then 
>> instead of simply returning, the escape continuation is called. This is done 
>> implicitly without specifying a named exception for returning and without 
>> defining some conditional structure on the side where it would return to.
>> 
>> This could all be wrong ...
> 
> It's at least a misconception.  Continuations are not exceptions - they are a 
> much lower level construct.  Exception handling is built on top of 
> continuations. 
> 
> There is nothing magic or mysterious about a continuation.  In Scheme, 
> continuations are the moral equivalent of GOTO with arguments [yes, you can 
> pass arguments to continuations].  In actual fact they can be used to write 
> code that jumps around arbitrarily ... but the standard uses are more 
> structured.  
> 
> When you say, (let/ec foo ... ) , all that's happening is the compiler 
> defines a pseudo-function named 'foo' that when called will exit from the 
> block of code in the scope of the let.  (call/cc foo  ...) does the same, but 
> assumes you will be immediately calling a function instead of executing 
> inline code.  Invoking foo anywhere in the function (or its descendants) will 
> jump back out of the call chain.  Scheme makes invoking the continuation look 
> like a function call even though it really is a jump that won't return.
> 
> You do need to learn about continuations because they are the underlying 
> basis of many programming techniques: exceptions, co-routines, threads, etc.  
> ... all of which can be implemented directly in Scheme without dipping into 
> assembler. 
>  
> Dan Friedman's paper is great, but is too technical and too Scheme-centric 
> for beginners.  The Wikipedia article on continuations 
> (https://en.wikipedia.org/wiki/Continuation 
> ) is simpler to understand.  Be 
> sure to look through the "further reading" and links at the end.  But the way 
> to really get a handle on what continuations are is to read a book on 
> compilers - at which point you'll realize that they really are little more 
> than a branch target.
> 
>> However, with this kind of idea about escape continuations in mind, I think 
>> I get the idea behind using `(let/ec` in the code. When a place wants to 
>> exit, it is stopped from doing so, giving it more work, as if to say: "Hey 
>> wait! You can escape, but only if you do THIS! (escape continuation)" Then 
>> the place, desperately wanting to escape thinks: "Damn, OK, I'll do just 
>> that little bit of code more.", not realizing, that it is stuck in a loop. 
>> How mean.
>> 
>> I wonder however, if there is no simpler way of doing this.
>> 
>> I mean, if `(place-channel-get ...)` blocks, could I simply put stuff into 
>> an endless loop without escape continuation and only break the loop, if a 
>> certain symbol is received on the channel?
> 
> How are you going to "break out" of the loop?  In Scheme there are only 3 
> ways to jump over or out of a block of code: return from a function, invoke a 
> continuation, or raise an exception.  The loop I wrote was in the middle of 
> the function where returning was not an option and there was no reason to 
> raise an exception.  Delimited (aka "escape") continuations are a structured 
> way to jump out of a loop.
> 
> A 'do' loop is a macro that hides continuations inside.  You might as well 
> learn to use them directly.
> 
>> Since `(place-channel-get ...)` is blocking, it should not generate any CPU 
>> load, when there is no message on the channel (right?).
>> 
>> Why do I need to introduce something as complex as `(let/ec ...)`?
> 
> Because you need to exit from of the - otherwise infinite - loop.  
> 
>> I appreciate the code shared here. I just hesitate to use it, when I don't 
>> even understand it myself or when I am super unsure about understanding it 
>> (escape continuations). I am also thinking about how I can replace all the 
>> exclamation mark procedures, before adding it to my other code, which does 
>> not deal with assignments so far.
> 
> Don't get too hung up on style points ... the goal is to write code that is 
> easy 

Re: [racket-users] Need help with parallelizing a procedure

2017-08-12 Thread Jon Zeppieri
On Sat, Aug 12, 2017 at 6:21 AM, Zelphir Kaltstahl
 wrote:
>
> ~~~
> (define (gini-index subsets label-column-index)
>   (for*/list ([subset (in-list subsets)]
>   [label (in-list (list 0 1))])
> (place pch
>(place-channel-put pch (list subset label label-column-index))
>(let ([data (place-channel-get pch)])
>  (calc-proportion (first data)
>   (second data)
>   (third data))
> ~~~
>
> The `subset` inside `(place-channel-put pch (list subset label 
> label-column-index))` gets underlined and the error is:
>
> subset: identifier used out of context

Two things:

First, regarding the above code, if you look at the docs for `place`,
you'll see: "The `body`s close only over `id` plus the *top-level*
bindings of the enclosing module..." [emphasis added]. You're trying
to treat `subset`, `label`, and `label-column-index` as if they were
in the new place's closure, but those bindings are all local, so
they're not available. In the Rosetta example you cited, `numbers` is
explicitly sent (via a `place-channel-put`) from the main place to the
newly created one. You'd need to do the same.

Second, though, you don't want to do this. Creating a place is
expensive enough that creating several each time you compute a gini
coefficient will probably make your code run very slowly. You mention
that you tried to use a place more than once. That's a better
approach. (Apparently, you had some trouble with that approach, but
yes, it can be done.)

However, you should try using futures instead of places. They're less
expensive to create and generally best suited for numeric tasks like
yours (as the Guide says -- and you should definitely read the section
of the Guide on parallelism
[http://docs.racket-lang.org/guide/parallelism.html].

- Jon

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[racket-users] Need help with parallelizing a procedure

2017-08-12 Thread Zelphir Kaltstahl
I want to parallelize a procedure which looks like this:

~~~
(define (gini-index subsets label-column-index)
  (for/sum ([subset (in-list subsets)])
(for/sum ([label (in-list (list 0 1))])
  (calc-proportion subset
   label
   label-column-index
~~~

I tried some variations of using places without success and then I found: 
https://rosettacode.org/wiki/Parallel_calculations#Racket

Where the code is:


~~~
#lang racket
(require math)
(provide main)
 
(define (smallest-factor n)
  (list (first (first (factorize n))) n))
 
(define numbers 
  '(112272537195293 112582718962171 112272537095293
115280098190773 115797840077099 1099726829285419))
 
(define (main)
  ; create as many instances of Racket as
  ; there are numbers:
  (define ps 
(for/list ([_ numbers])
  (place ch
 (place-channel-put 
  ch
  (smallest-factor
   (place-channel-get ch))
  ; send the numbers to the instances:
  (map place-channel-put ps numbers)
  ; get the results and find the maximum:
  (argmax first (map place-channel-get ps)))
~~~

So inside the list places are created and it seems that the whole definition of 
what they are supposed to do is wrapped in that (place ...) expression. I tried 
to do the same for my example:

~~~
(define (gini-index subsets label-column-index)
  (for*/list ([subset (in-list subsets)]
  [label (in-list (list 0 1))])
(place pch
   (place-channel-put pch (list subset label label-column-index))
   (let ([data (place-channel-get pch)])
 (calc-proportion (first data)
  (second data)
  (third data))
~~~

The `subset` inside `(place-channel-put pch (list subset label 
label-column-index))` gets underlined and the error is:

subset: identifier used out of context

(I) In the example from Rosetta code it is all easy, as here is only passed one 
number and is does not need a name or anything, but in my example I am not sure 
how to do it.

(II) A second thing I tried to do was using a place more than once (put, get 
then put get to the channel again), but it did not work and my program simply 
did nothing anymore, no cpu load or anything, but also did not finish, probably 
waiting for an answer from the place and never getting any. Is it in general 
not possible to use a place more than once?

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.