Некоторые ответы выше, использующие func_wrapper
и threading.Timer
, действительно работают, за исключением того, что он порождает новый поток каждый раз, когда вызывается интервал, что вызывает проблемы с памятью.
В базовом примере ниже примерно реализован аналогичный механизм, помещающий интервал в отдельный поток.Он спит с заданным интервалом.Прежде чем переходить к коду, вот некоторые ограничения, о которых вам нужно знать:
JavaScript является однопоточным, поэтому, когда функция внутри setInterval
запускается, больше ничего не будетработать одновременно (исключая рабочий поток, но давайте поговорим об общем случае использования setInterval
. Следовательно, многопоточность безопасна. Но здесь, в этой реализации, вы можете столкнуться с условиями гонки, если не используете threading.rLock
.
Приведенная ниже реализация использует time.sleep
для имитации интервалов, но если добавить время выполнения func
, общее время для этого интервала может оказаться больше, чем вы ожидаете.в зависимости от вариантов использования, вы можете захотеть «меньше спать» (минус время, потраченное на вызов func
)
Я только примерно проверил это, и вы должныопределенно не используйте глобальные переменные так, как я, не стесняйтесь настраивать их так, чтобы они подходили для вашей системы.
Хватит говорить, вот код:
# Python 2.7
import threading
import time
class Interval(object):
def __init__(self):
self.daemon_alive = True
self.thread = None # keep a reference to the thread so that we can "join"
def ticktock(self, interval, func):
while self.daemon_alive:
time.sleep(interval)
func()
num = 0
def print_num():
global num
num += 1
print 'num + 1 = ', num
def print_negative_num():
global num
print '-num = ', num * -1
intervals = {} # keep track of intervals
g_id_counter = 0 # roughly generate ids for intervals
def set_interval(interval, func):
global g_id_counter
interval_obj = Interval()
# Put this interval on a new thread
t = threading.Thread(target=interval_obj.ticktock, args=(interval, func))
t.setDaemon(True)
interval_obj.thread = t
t.start()
# Register this interval so that we can clear it later
# using roughly generated id
interval_id = g_id_counter
g_id_counter += 1
intervals[interval_id] = interval_obj
# return interval id like it does in JavaScript
return interval_id
def clear_interval(interval_id):
# terminate this interval's while loop
intervals[interval_id].daemon_alive = False
# kill the thread
intervals[interval_id].thread.join()
# pop out the interval from registry for reusing
intervals.pop(interval_id)
if __name__ == '__main__':
num_interval = set_interval(1, print_num)
neg_interval = set_interval(3, print_negative_num)
time.sleep(10) # Sleep 10 seconds on main thread to let interval run
clear_interval(num_interval)
clear_interval(neg_interval)
print "- Are intervals all cleared?"
time.sleep(3) # check if both intervals are stopped (not printing)
print "- Yup, time to get beers"
Exожидаемый вывод:
num + 1 = 1
num + 1 = 2
-num = -2
num + 1 = 3
num + 1 = 4
num + 1 = 5
-num = -5
num + 1 = 6
num + 1 = 7
num + 1 = 8
-num = -8
num + 1 = 9
num + 1 = 10
-num = -10
Are intervals all cleared?
Yup, time to get beers