2

I have struggled with this question for about a week -- time to ask someone who can bang out an answer in a couple minutes.

I am trying to run a python program once every 10 seconds. There are a lot of questions of this sort : Use sched module to run at a given time, Python threading.timer - repeat function every 'n' seconds, How to execute a function asynchronously every 60 seconds in Python?

Normally the solutions using sched or time.sleep would work, but I am trying to start a scheduled process from within cmd2, which is already running in a while False loop. (When you exit cmd2, it exits this loop).

Because of this, when I start a function to repeat every 10 seconds, I enter another loop nested within cmd2 and I am unable to enter cmd2 commands. I can only get back to cmd2 by exiting the sub-loop that is repeating the function, and thus the function stops repeating.

Evidently threading will solve this problem. I have tried threading.Timer without success. Perhaps the real problem is that I do not understand threads or multiprocessing.

Here is an example of code that is roughly isomorphic to the code I'm using, using sched module, which I got to work:

    import cmd2
    import repeated

    class prompt(cmd2.Cmd):
    """this lets you enter commands"""

        def default(self, line):
            return cmd2.Cmd.default(self, line)

        def do_exit(self, line):
            return True

        def do_repeated(self, line):
            repeated.func_1() 

Where repeated.py looks like this:

    import sched
    import time

    def func_2(sc):
        print 'doing stuff'
        sc.enter(10, 0, func_2, (sc,))


    def func_1():
        s = sched.scheduler(time.time, time.sleep)
        s.enter(0, 0, func_2, (s,))
        s.run()
Community
  • 1
  • 1
Wapiti
  • 1,851
  • 2
  • 20
  • 40

2 Answers2

3

http://docs.python.org/2/library/queue.html?highlight=queue#Queue

Can you instance a Queue object outside of cmd2? There can be one thread that watches the queue and takes jobs from it at periodic intervals; while cmd2 is free to run or not run. The thread that processes the queue, and the queue object itself need to be in the outer scope, of course.

To schedule something at a particular time, you can insert a tuple which has the target time in it. Or you can have the thread just check at regular intervals, if that's good enough.

[Edit, if you have a process that is intended to repeat, you can have it requeue itself at the end of it's operation.]

Mayur Patel
  • 945
  • 1
  • 7
  • 15
  • Thanks for this, I wasn't aware of Queue. It looks like it will do what I am looking for. However, I found a simpler way with threading.Timer (which is the preferred way judging from the number of answers using it) and have outlined it below. – Wapiti Feb 08 '14 at 00:27
2

As soon as I asked the question I was able to figure it out. Don't know why that happens sometimes.

This code

def f():
    # do something here ...
    # call f() again in 60 seconds
    threading.Timer(60, f).start()

# start calling f now and every 60 sec thereafter
f()

From here: How to execute a function asynchronously every 60 seconds in Python?

Actually works for what I was trying to do. There are evidently some subtleties in how the function is called as an argument in threading.Timer. Before when I was including the arguments and even the parentheses after the function I was getting recursive depth errors --i.e. the function was calling itself without delay constantly.

So anyone else who has a problem like this, pay attention to how you call the function in threading.Timer(60, f).start(). If you write threading.Timer(60, f()).start() or something similar it will probably not work.

Community
  • 1
  • 1
Wapiti
  • 1,851
  • 2
  • 20
  • 40