August'24: Kamaelia is in maintenance mode and will recieve periodic updates, about twice a year, primarily targeted around Python 3 and ecosystem compatibility. PRs are always welcome. Latest Release: 1.14.32 (2024/3/24)

Axon.Component.py

Version: Axon 1.0

TODO:Document the fact that runBody is actually the main() function, and hence using a standard generator where main() is, is fine.

TODO:Make a note that microthread is meant as a term to mean "active generator object". (This was written during python 2.2 days when generators were uncommon, hence convoluted over explanation)

TODO:Generally chop down and rewrite better

A component is a microprocess with a microthread of control, input/output queues (inboxes/ outboxes) connected by linkages to other components, with postmen taking messages from output queues, passing them along linkages to inboxes.

A microprocess is a class that supports parallel execution using microthreads.

A microthread takes more explanation is a thread of control resulting from a function of the following form:

deffoo():

yield1
while1:

bla = foo() results in bla containing an intelligent function representing the thread of control inside the function - in this case inside the while loop - that remembers where the program counter was when control was yielded back to the caller. Repeated calls to bla.next() continue where you left off.

First call to bla() & you get "this" printed. Next time you get "that" then "this" printed (when you go back round the loop). The time after that, you get "that" then "this" printed, and so on.

If you have 10 calls to foo() you end up with 10 function calls that remember where they were in foo(), which run for a bit and then return control back to the caller. If you repeatedly call all of these function calls, you essentially end up with foo() running 10 times in parallel. It's these special "position remembering" functions that get termed microthreads.

Clearly in order to have a microthread, you have to have a piece of code capable of being called in this manner - ie it yields control back to it's caller periodically - this is a what a microprocess in this context. An object that has a "special method" that can be treated in this manner.

A component puts a layer of wrapper on top of the microprocess, which adds in input & output queues (inboxes/outboxes). To make life easier, a component has some wrappers around the "special function" to make user code less obfuscated. The life cycle for a component runs as follows:

myComponent gets activated at some point later.

When myComponent is activated the following logic happens for the runtime of myComponent :

defrunComponent(someComponent):

result = someComponent.initialiseComponent()
ifresult:yieldresult
result = 1
whileresult:

someComponent.closeDownComponent
yieldresult
# Component ceases running

Dummy methods for the methods listed here are provided, so missing these out won't result in broken code. The upshot is a user component can look like this:

classmyComponent(component):

count = 0
def__init__(self,somearg):

definitialiseComponent(self):

defmainLoop(self):

defcloseDownComponent(self):

This creates a component class which has the default input/output boxes of "inbox" and "outbox".

Pydoc Style Documentation

class component(Axon.Microprocess.microprocess)

Method resolution order:

Data and other attributes defined here:

Methods defined here:

__init__(self)

__str__(self)

addChildren(self, *children)

childComponents(self)

closeDownComponent(self)

dataReady(self, boxname='inbox')

initialiseComponent(self)

link(self, source, sink, passthrough=0, pipewidth=0, synchronous=None)

main(self)

mainBody(self)

recv(self, boxname='inbox')

removeChild(self, child)

send(self, message, boxname='outbox', force=False)

synchronisedSend(self, thingsToSend, outbox='outbox')

C.synchronisedSend(list, of, things,to, send) -> generator for sending the objects when space is available. Expected to be used as:

foriinself.synchronisedSend(thingsToSend):

Largely has to be done that way due to not being able to wrap yield. See test/SynchronousLinks_SystemTest.py for an example

Testdoc Documentation

__init__

__str__

addChildren

childComponents

closeDownComponent

dataReady

initialiseComponent

link

main

mainBody

recv

removeChild

send

synchronisedBox

synchronisedSend

_activityCreator

_closeDownMicroprocess

_collect

_collectInbox

_deliver

_passThroughDeliverIn

_passThroughDeliverOut

_passThroughDeliverOut_Sync

_safeCollect

__addChild

Michael, December 2004