Esempio n. 1
0
class IntervalTrigger():
    '''Generate signals at a regular interval up to total_signals'''

    total_signals = IntProperty(title="Total Number of Signals", default=-1)
    interval = TimeDeltaProperty(title='Interval', default={'seconds': 1})

    def __init__(self):
        super().__init__()
        self._stop_event = Event()
        self.counter = None

    def start(self):
        super().start()
        self.counter = 0
        self._stop_event.clear()
        spawn(self.run)

    def run(self):
        # We'll keep track of when each iteration is expected to finish
        interval_secs = self.interval.total_seconds()
        expected_finish = time() + interval_secs

        while not self._stop_event.is_set():
            sigs = self.generate_signals()

            # If a generator is returned, build the list
            if not isinstance(sigs, list):
                sigs = list(sigs)

            # Add however many signals were generated (in case multiple
            # signals mixin was used) to the counter and notify them
            self.counter += len(sigs)
            self.notify_signals(sigs)

            if self.total_signals > 0 and self.counter >= self.total_signals:
                # We have reached our total, stop
                break

            # sleep the exact correct amount of time
            time_remaining = expected_finish - time()
            if time_remaining > 0:
                # If we have time remaining, sleep until the next iteration
                sleep(time_remaining)

            # One iteration is complete, increment our next "expected finish"
            # time. This expected_finish could fall behind the actual time
            # if it takes longer than interval_secs to generate the signals
            expected_finish += interval_secs

    def stop(self):
        """ Stop the simulator thread. """
        self._stop_event.set()
        super().stop()
Esempio n. 2
0
class SafeTrigger():

    """ Guarantees notifying signals every interval, regardless of count """

    interval = TimeDeltaProperty(title='Interval', default={'seconds': 1})
    max_count = IntProperty(title='Max Count', default=1)

    def __init__(self):
        super().__init__()
        self._job = None
        self.stop_event = Event()
        self.signal_lock = Lock()

    def start(self):
        super().start()
        self._job = Job(self._emit, self.interval, True)
        # Run an emit cycle immediately, but in a new thread since it
        # might take some time and we don't want it to hold up start
        spawn(self._emit)

    def stop(self):
        """ Stop the simulator thread and signal generation """
        if self._job:
            self._job.cancel()

        self.stop_event.set()
        super().stop()

    def _emit(self):
        """ Called every *interval* to generate then notify the signals """
        self._logger.debug("New generation cycle requested")
        count = 0
        signals = []

        # Stop any currently running simulator threads
        self.stop_event.set()
        # We only want one simulator thread simulating at a time
        with self.signal_lock:
            # Ok, we're running, so clear the event and wait
            self.stop_event.clear()
            self._logger.debug("Starting generation...")
            while count < self.max_count and not self.stop_event.is_set():
                signals.extend(self.generate_signals(1))
                count += 1

        self._logger.debug("Notifying {} signals".format(len(signals)))
        self.notify_signals(signals)