3

I have a scenario where I am using the python circuits framework to dynamically create new components which have their own channel. I would like to be notified when ALL of the created channels have fired a particular event.

I have tried using the success event but this fires on each channel independently, so I get one per channel. It makes sense for me to use different channels as the same tasks are being carried out on different data sets.

My current solution is to record the created channel names and then listen for the finishing event ("boom" below) and remove the firing channel from a list. When the list is empty I can stop. An example of this is below. It works, but I feel there should be a more elegant way of joining these channels once they have finished.

import time
import sys

from circuits import Component, Event
from circuits.core.debugger import Debugger

class boom(Event):
    "boom event"

class Start(Component):
    def __init__(self, channel="*"):
        super(Start, self).__init__(channel=channel)
        self._boom_channels = []
        return

    def started(self, *args):
        for i in [1,2]:
            channel = 'channel_{}'.format(i)
            self._boom_channels.append(channel)

            new = Middle(channel=channel).register(self)

    def boom(self, event, *args):
        new_chans = set(self._boom_channels) - set(event.channels)
        self._boom_channels = list(new_chans)
        print self._boom_channels
        if not self._boom_channels:
            sys.exit()

class Middle(Component):
    def __init__(self, channel="*"):
        super(Middle, self).__init__(channel=channel)
        time.sleep(2)
        self.fire(boom())
        return

if __name__ == '__main__':
    (Start() + Debugger()).run()
James Mills
  • 18,669
  • 3
  • 49
  • 62
H0R5E
  • 65
  • 6
  • Sorry for the delayed response here I didn't see this question until now... I'll answer this ASAP. --JamesMills / prologic (developer of circuits) – James Mills Mar 18 '15 at 02:13

1 Answers1

1

I believe you have the right idea here. As these are diescrete events there is no way to identify when they are all complete without tracking them (I don't think).

The only way I'd make your example better is:

#!/usr/bin/env python


from __future__ import print_function


from circuits import Component, Debugger, Event


class boom(Event):
    "boom event"


class Start(Component):

    channel = "start"

    def init(self, channel=channel):
        self.boom_channels = []

    def started(self, *args):
        for i in [1, 2]:
            channel = "channel_{}".format(i)
            self.boom_channels.append(channel)

            Middle(channel=channel).register(self)

    def boom(self, middle):
        self.boom_channels.remove(middle.channel)

        if not self.boom_channels:
            raise SystemExit(0)


class Middle(Component):

    def registered(self, component, manager):
        self.fire(boom(self), manager)
        return


def main():
    app = (Start() + Debugger())
    app.run()


if __name__ == '__main__':
    main()

With output:

$ python test.py 
<registered[*] (<Debugger/* 1156:MainThread (queued=0) [S]>, <Start/start 1156:MainThread (queued=2) [R]> )>
<started[start] (<Start/start 1156:MainThread (queued=1) [R]> )>
<registered[channel_1] (<Middle/channel_1 1156:MainThread (queued=0) [S]>, <Start/start 1156:MainThread (queued=2) [R]> )>
<registered[channel_2] (<Middle/channel_2 1156:MainThread (queued=0) [S]>, <Start/start 1156:MainThread (queued=2) [R]> )>
<boom[<Start/start 1156:MainThread (queued=2) [R]>] (<Middle/channel_1 1156:MainThread (queued=0) [S]> )>
<boom[<Start/start 1156:MainThread (queued=1) [R]>] (<Middle/channel_2 1156:MainThread (queued=0) [S]> )>
<stopped[start] (<Start/start 1156:MainThread (queued=0) [S]> )>

EDIT: A couple of notes:

  • Explicitly push the boom() event to the manager.
  • Fire the boom() event "after" we're registered.
James Mills
  • 18,669
  • 3
  • 49
  • 62