1

In my .py script I have 2 functions. One of them should be called every 5 minutes, and the other should be called every 4 hours. The second one, however, only runs once when the script is ran and never again (while the 5 minute function works fine).

#!/usr/bin/env python
import threading

def five_min(): 
    threading.Timer(300, five_min).start()
    print("5 min")
def four_h():
    threading.Timer(14400, four_h).start()
    print("4 h")

five_min()
four_h()

This is the whole code, I'm running it on Linux(Raspberry Pi)

P.S. I think that the problem could be that 4_h function is interrupted by 5_min function.

opengl
  • 141
  • 1
  • 5
  • 15

4 Answers4

2

Your four_hour function may be raising an exception before threading.Timer().start() is called again:

import threading
import logging
logger = logging.getLogger(__name__)

def five_min(): 
    t = threading.Timer(5, five_min).start()
    logger.info("5 min")
def four_hour():
    1/0  # <-- Raise an exception
    threading.Timer(4, four_hour).start()
    logger.info("4 h")

logging.basicConfig(level=logging.DEBUG,
                    format='[%(asctime)s %(threadName)s] %(message)s',
                    datefmt='%M:%S')

five_min()
four_hour()

yields

[57:54 MainThread] 5 min
Traceback (most recent call last):
  File "script.py", line 21, in <module>
    four_hour()
  File "script.py", line 12, in four_hour
    1/0
ZeroDivisionError: integer division or modulo by zero
[57:59 Thread-1] 5 min
[58:04 Thread-2] 5 min
...

(Note: I changed the delays so the script is easier to test. Once you are satisfied with the script's qualitative behaviour, you can the delays as you desire.)


Note: as clemtoy points out, as long as there is no need for inter-thread or inter-process communication, it may be easier to use cron to call separate scripts which run the five_min and four_hour functions. If you do need inter-process communication, it may still be better to use cron, but you'd have to structure your code differently, perhaps reading from a database to learn the state of erstwhile global variables.

Community
  • 1
  • 1
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • In original code the functions are called differently, 5_min, 4_h are only names for example. Sorry for confusion – opengl Jul 05 '15 at 16:56
0

I also believe the problem is that 4_h() is interrupted by the other function. You could create a counter var inside 5_min and call 4_h() from there.

#!/usr/bin/env python

import threading

counter = 0
def 5_min(): 
    threading.Timer(300, 5_min).start()
    counter += 1
    if (counter == 48):
        counter = 0
        4_h()
    print("5 min")
def 4_h():
    ...

It is probably not the best solution, but is the best one I know.

jjimenezg93
  • 162
  • 4
  • 16
0

In my view, the best way to plan tasks on linux is to use cron. If you want your script to add the task itself to the linux crontab, you should look at the python-crontab package.

clemtoy
  • 1,681
  • 2
  • 18
  • 30
  • The problem with crontab is that is "resets" all variables values, while I store data in my array that needs to be saved while script is running. – opengl Jul 05 '15 at 17:35
0

Aside the syntax now. I would suggest you doing it this way:

from threading import Timer
s = 0; m = 0
fivesec_timer = None
fourmin_timer = None
def fivesec ():
    global fivesec_timer, s
    print s, "seconds passed after start"
    s += 5
    fivesec_timer = Timer(5, fivesec)
    fivesec_timer.start()

def fourmin ():
    global fourmin_timer, m
    print m, "minutes passed after start"
    m += 4
    fourmin_timer = Timer(4*60, fourmin)
    fourmin_timer.start()

fivesec()
fourmin()
# Here some code and blocking code
# For instance:
raw_input()
fivesec_timer.cancel()
fourmin_timer.cancel()

This way, you can control your timers outside your functions.

Don't do Timer(...).start(), especialy not inside a function (local scope).
It should work fine, but you never know what and when garbage collector would clean up or something else occurs. You do not know how the _Timer() is implemented internally.
And you don't have a hard reference to the timer (in a var) all the time.
Mutual canceling out was probably caused by that, although this is clear speculation.
threading module is well tested, yet you experienced problems. Keep your code neat. Best to be sure.
Well, that is my view of the world. Someone will not agree. :D
Dalen
  • 4,128
  • 1
  • 17
  • 35