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)
likefile is a way to run Axon components with code that is not Axon-aware. It does this by running the scheduler and all associated microprocesses in a separate thread, and using a custom component to communicate if so desired.
With a normal kamaelia system, you would start up a component and start running the Axon scheduler as follows, either:
from Axon.Scheduler import scheduler
component.activate()
scheduler.run.runThreads()
someOtherCode()
or simply:
component.run()
someOtherCode()
In both cases, someOtherCode() only run when the scheduler exits. What do you do if you want to (e.g.) run this alongside another external library that has the same requirement?
Well, first we start the Axon scheduler in the background as follows:
from likefile import background
background().start()
The scheduler is now actively running in the background, and you can start components on it from the foreground, in the same way as you would from inside kamaelia (don't worry, activate() is threadsafe):
component.activate()
someOtherCode()
"component" will immediately start running and processing. This is fine if it's something non-interactive like a TCP server, but what do we do if we want to interact with this component from someOtherCode?
In this case, we use 'likefile', instead of activating. This is a wrapper which sits around a component and provides a threadsafe way to interact with it, whilst it is running in the backgrounded scheduler:
from Axon.LikeFile import likefile
wrappedComponent = likefile(component)
someOtherCode()
Now, wrappedComponent is an instance of the likefile wrapper, and you can interact with "component" by calling get() on wrappedComponent, to get data from the outbox on "component", or by calling put(data) to put "data" into the inbox of "component" like so:
p = likefile( SimpleHTTPClient() )
p.put("http://google.com")
google = p.get()
p.shutdown()
print "google's homepage is", len(google), "bytes long.
for both get() and put(), there is an optional extra parameter boxname, allowing you to interact with different boxes, for example to send a message with the text "RELOAD" to a component's control inbox, you would do:
wrappedComponent.put("RELOAD", "control")
wrappedComponent.get("signal")
Finally, likefile objects have a shutdown() method that sends the usual Axon IPC shutdown messages to a wrapped component, and prevents further IO.
likefile has some optional extra arguments on creation, for handling custom boxes outside the "basic 4". For example, to wrap a component with inboxes called "secondary" and "tertiary" and an outbox called "debug", You would do:
p = likefile( componentMaker,
extraInboxes = ("secondary", "tertiary"),
extraOutboxes = "debug", )
Either strings or tuples of strings will work.
It may be the case that the component you are trying to wrap will link its own inbox/outbox/signal/control, and this will result in a BoxAlreadyLinkedToDestination exception. To stop likefile from wrapping the default 4 boxes, pass the parameter wrapDefault = False. Note that you will need to manually wrap every box you want to use, for example to wrap a component that has its own linkages for signal/control:
p = likefile( myComponent,
wrapDefault = False,
extraInboxes = "inbox",
extraOutboxes = "outbox", )
likefile is constructed from components like so:
+----------------------------------+
| likefile |
+----------------------------------+
| / \
| |
InQueues OutQueues
| |
+---------+-----------------------+---------+
| \ / | |
| +---------+ +--------+ |
| | Input | Shutdown | Output | |
| | Wrapper | ------------> | | |
| | (thread)| Message |Wrapper | |
| +---------+ +--------+ |
| | / \ |
| | | |
| Inboxes Outboxes |
| | | |
| \ / | |
| +----------------------------------+ |
| | the wrapped component | |
| +----------------------------------+ |
| |
| +----------------------------------+ |
| | Some other component | |
| | that was only activated | |
| +----------------------------------+ |
| |
| AXON SCHEDULED COMPONENTS |
+-------------------------------------------+
Note 1: Threadsafeness of activate().
when a component is activated, it calls the method inherited from microprocess, which calls _addThread(self) on an appropriate scheduler. _addThread calls wakeThread, which places the request on a threadsafe queue.
Add an extra wrapped box called name, using the addBox function provided (either self.addInbox or self.addOutbox), and adding it to the box mapping which is used to coordinate message routing within component wrappers.
A python thread which runs a scheduler. Takes the same arguments at creation that scheduler.run.runThreads accepts.
A wrapper that takes a child component and waits on an event from the foreground, to signal that there is queued data to be placed on the child's inboxes.
This method checks all the queues from the outside world, and forwards any waiting data to the child component. Returns False if we propogated a shutdown signal, true otherwise.
A component which takes a child component and connects its outboxes to queues, which communicate with the likefile component.
This method will take any outgoing data sent to us from a child component and stick it on a queue to the outside world.
A dummy component. Functionality: None. Prevents the scheduler from dying immediately.
An interface to the message queues from a wrapped component, which is activated on a backgrounded scheduler.
Return True if there is no data pending collection on boxname, False otherwise.
Performs a blocking read on the queue corresponding to the named outbox on the wrapped component. raises AttributeError if the likefile is not alive. Optional parameters blocking and timeout function the same way as in Queue objects, since that is what's used under the surface.
Equivalent to get(boxname, False)
Places an object on a queue which will be directed to a named inbox on the wrapped component.
Returns the approximate number of pending data items awaiting collection from boxname. Will never be smaller than the actual amount.
Sends terminatory signals to the wrapped component, and shut down the componentWrapper. will warn if the shutdown took too long to confirm in action.
Got a problem with the documentation? Something unclear that could be clearer? Want to help improve it? Constructive criticism is very welcome - especially if you can suggest a better rewording!
Please leave you feedback here in reply to the documentation thread in the Kamaelia blog.
-- Automatic documentation generator, 09 Dec 2009 at 04:00:25 UTC/GMT