Below I have re-worked the example program you sent yesterday to send all
the work to an explicitly-created place-channel, from which all of the
worker places can get work.

I also saw your question about sending procedures to places. The module
web-server/lang/serial-lambda provides the serial-lambda form, but creates
procedures that can be serialized using racket/serialize (as long as the
contents of the closure are serializable):
http://docs.racket-lang.org/web-server-internal/closure.html Once
serialized, these can be passed through place-channels, and they are far
more robust than using eval. In general, the documentation for
place-message-allowed? specifies what kind of messages can be passed
through place-channels:
http://docs.racket-lang.org/reference/places.html?q=place-message-allowed%3F#%28def._%28%28lib._racket%2Fplace..rkt%29._place-message-allowed~3f%29%29

#lang racket

(define (place-output out-ch . args)
  (place-channel-put out-ch args))

(define (make-out-ch)
  (define-values (in-ch out-ch)
    (place-channel))
  (thread (λ ()
            (let loop ()
              (apply printf (sync in-ch))
              (newline)
              (loop))))
  out-ch)

(define (start-places get-work-pch out-ch)
  (for/list ([place-id (processor-count)])
    (define place
      (place/context terminate-pch
        (place-output out-ch "place starting")
        (let loop ()
          (sync (handle-evt
                 terminate-pch
                 (λ (_)
                   (place-output out-ch
                                 "Place ~s is going to finish now."
                                 place-id)))
                (handle-evt
                 get-work-pch
                 (λ (data)
                   (place-output out-ch
                                 "Place ~s got the following work: ~a."
                                 place-id
                                 data)
                   (place-channel-put get-work-pch place-id)
                   (loop)))))))
    (place-output out-ch "created place ~s" place-id)
    place))

(define (stop-places places)
  ;; simply terminate all places
  (for ([a-place (in-list places)])
    (place-channel-put a-place 'terminate))
  (for ([a-place (in-list places)])
    (place-wait a-place)))

(define (main [messages '(the quick brown fox jumped over the lazy dogs)])
  (define-values (send-work-pch get-work-pch)
    ;; this must not be at the module level, or each place will
    ;; get its own version
    (place-channel))
  (define out-ch
    (make-out-ch))
  (define places
    (start-places get-work-pch out-ch))
  (sleep 1)
  (define num-messages
    (for/fold ([n 0])
              ([message messages])
      (place-channel-put send-work-pch message)
      (add1 n)))
  (place-output out-ch "main has no more work data")
  (let loop ([done 0])
    (unless (= done num-messages)
      (sync send-work-pch)
      (loop (add1 done))))
  (place-output out-ch "all work reports finished")
  (stop-places places))

(module* main #f
  (main))

-Philip

On Sun, Jan 14, 2018 at 8:18 AM, Zelphir Kaltstahl <
[email protected]> wrote:

> I also found the following post on StackOverflow:
> https://stackoverflow.com/a/19095650/1829329
>
> There the following timeout using construct is used:
>
> ~~~
>
> (let loop ((i 0) (res '()))                      ; response loop
>     (if (= i l)
>         (reverse res)
>         (let ((response (sync/timeout 10 wch-c)))  ; get answer with timeout 
> (place-channel-get blocks!)
>           (loop
>            (+ i 1)
>            (if response (cons response res) res))))))
>
> ~~~
>
> But it is not perfect, because the timeout time is wasted and could
> already be used to distribute more work.
>
>
> On Sunday, January 14, 2018 at 3:15:23 PM UTC+1, Zelphir Kaltstahl wrote:
>>
>> I have multiple places on which I would like to distribute some "work". I
>> don't have a clear idea yet what that might be, so it is currently
>> something abstract, which I don't want to make many assumptions about.
>> Preferably I would like it to be so generic, that it could be anything.
>> This is conceptually a "pool of places" I think. Such a pool of places is
>> nice to have, because one does not always know the best way to parallelize
>> things, unless it is a very simple case, where computation of all work
>> items takes the same amount of time. With a pool which distributes the work
>> itself, always giving the idle places work to do, it is like filling
>> multiple containers with sand, rather than big stones which would leave
>> gaps.
>>
>> I would like to "listen" on the channels of the places, until there is a
>> message and then react on the message.
>> The docs
>> <https://docs.racket-lang.org/reference/places.html?q=place*#%28def._%28%28lib._racket%2Fplace..rkt%29._place-channel-get%29%29>
>> say that `place-channel-get` is blocking. I also found the asynchronous
>> buffered channels docs
>> <https://docs.racket-lang.org/reference/async-channel.html>, but do not
>> know if or how I could use them with places, or whether they are only for
>> threads.
>> The place-channel-get being blocking means that if I use that my work
>> distribution would be blocked until I get some message from that place on
>> its channel.
>> The progress of computation would depend on that one checked channel
>> giving me a message.
>>
>> I was thinking about putting such checks in threads, one for each
>> channel, and then re-creating any thread that returns with some message
>> from its place to send more work and get more messages, except if the work
>> has all been distributed or the place has terminated.
>> Somehow I would need to let the threads call a procedure to let them
>> "signal", that they returned.
>> Maybe 1 procedure for getting more work on the place and 1 procedure for
>> signaling termination of the place.
>> Otherwise I'd be doing busy wait again checking the threads for results,
>> as I would have checked the channels without threads.
>>
>> But then I probably run into the next problem: How to manage the total
>> available amount of work in a thread-safe manner?
>>
>> Is this even a feasible approach?
>> Has there been work done that enables arbitrary computation (determined
>> at run time, not compile time) in places distributing work to the places
>> whenever they are no longer working on something?
>>
>>
>>
> --
> 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 [email protected].
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to