I've not posted this code because it previously hadn't been used in more 
than one (private) project, but it seems to hold water in 2 different 
projects (one is some IOT work from a year ago, one is a private work 
project I can't discuss at the moment), so I'm posting  a link to it here 
for interest.

What is Guild? Well in a very short word, is a Kamaelia style Actor 
library. Previously in a Kamaelia presentation about concurrency...

http://www.slideshare.net/kamaelian/kamaelia-lightning2010opensource

... I noted that the actor model is where you have active objects with an 
inbox, whereas Kamaelia's outboxes would map to late binding in the actor 
model. (see slides 10 and 11)

What does this mean for Kamaelia? It means that inboxes now look like 
methods - decorated as actor methods. It means that outboxes also look like 
methods, decorated as late_bind or late_bind_safe. There is a default 
implementation for an "output" method - which is late_bind-able

This means a simple transformer component now becomes:

from guild import * 

class CapStream(Actor):
    @actor_method
    def input(self, data):
      self.output(str.capitalize(data)  )

Something that actively "ticks" would look like this:
class Ticker(Actor):
    @process_method
    def process(self):
        time.sleep(0.5)
        self.output( "hello world" )

As usual, interesting things are made by joining components together.  Some 
initial utility components/actors already exist

from guild.components import Printer

cap_stream = CapStream()
ticker  = Ticker()
printer = Printer()

pipe(ticker, "output", cap_stream, "input")
pipe(cap_stream, "output", printer, "input")

start(cap_stream, ticker, printer)
time.sleep(2)
stop(cap_stream, ticker, printer)
wait_for(cap_stream, ticker, printer)

The start/stop/wait_for calls are necessary because we're dealing with 
separate threads rather than a scheduler. This may improve, but it's 
perhaps worth noting that this will shutdown cleanly, even though it 
launches a bunch of threads.

The word "output" is the name of a late_bind (or late_bind_safe) method in 
the source object and the word "input" is the name of an actor_method in 
another Actor. 

The the av test code, it used:
        pipe(wct, "produce", d, "show") 

Where wct is a web cam component ,and d is a display component. The webcam 
calls self.produce() when a frame is ready. The pipe forces that frame to 
be passed to the display's "show" actor method.
Snipping the last parts of these, they look like this:

class WebCamTest(Actor):
[ .. snip .. ]
    @late_bind
    def produce(self, image, timestamp):
        pass

class SomeDisplay(Actor):
[ .. snip .. ]
    @actor_method
    def show(self,image, timestamp):
        # pass
        self.frames.append((image, timestamp))
        self.display.blit(image, (0,0) )
        pygame.display.flip()

This avoids the whole idiom of "if self.dataReady("..."): x = self.recv()" 
and so on.

If the methods used by all your components for output are called "output", 
and all the inputs are called "input" the actor method becomes 
pipelineable. For example the above example becomes this:

from guild import * 
from guild.components import Printer

class CapStream(Actor):
    @actor_method
    def input(self, data):
      self.output(str.capitalize(data)  )

class Ticker(Actor):
    @process_method
    def process(self):
        time.sleep(0.5)
        self.output( "hello world" )

cap_stream = CapStream()
ticker  = Ticker()
printer = Printer()

pipeline(ticker, cap_stream, printer)
start(cap_stream, ticker, printer)
time.sleep(2)
stop(cap_stream, ticker, printer)
wait_for(cap_stream, ticker, printer)

Likewise, if you have a component where "produce" and "show" make more 
sense than "output" and "input" then you can add aliases:

class WebCamTest(Actor):
    [ .. snip .. ]
    @late_bind
    def produce(self, image, timestamp):
        pass

    output = produce


class SomeDisplay(Actor):
    [ .. snip .. ]
    @actor_method
    def show(self,image, timestamp):
        # pass
        self.frames.append((image, timestamp))
        self.display.blit(image, (0,0) )
        pygame.display.flip()

    input = show

Which then allows things like:

webcam = WebCamTest()
display = SomeDisplay()

pipeline(webcam, display)

start(webcam, display)
time.sleep(2)
stop(webcam, display)
wait_for(webcam, display)

Not saying this is perfect, there's certainly some things I want to improve 
here to make
the syntactic sugar nicer, but this strikes me as a good start!

As I say, the code is here at the moment:
   https://github.com/sparkslabs/guild

And hopefully should grow sufficient extras to allow interoperation with 
kamaelia, and
later hopefully supplant it.

No benchmarking done on it as yet, but it runs sufficiently fast for my 
needs at present.

The 99 bottles code looks like this:
   - https://github.com/sparkslabs/guild/blob/master/examples/99bottles.py

It also supports things like backplanes, and STM by default.

Any comments welcome. Mainly forwarding because I'm finding this useful at 
the moment, and will probably extend in some interesting ways.


Michael.

-- 
You received this message because you are subscribed to the Google Groups 
"kamaelia" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to kamaelia+unsubscr...@googlegroups.com.
To post to this group, send email to kamaelia@googlegroups.com.
Visit this group at http://groups.google.com/group/kamaelia.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to