(Python) 如何通过函数传递 threading.Thread 对象?
我有一个定时器功能:
# This is a class that schedules tasks. It will call it's ring() function
# when the timer starts, and call it's running() function when within the
# time limit, and call it's over() function when the time is up.
# This class uses SYSTEM time.
import time, threading
import settings
from object import Object
class Timer(Object, threading.Thread):
# INIT -------------------------------------------------------------
# Init vars
#
# If autotick is True (default) the timer will run in a seperate
# process. Other wise it will need to be updated automatically by
# calling tick()
def __init__(self, autotick=False):
# Call inherited __init__ first.
threading.Thread.__init__(self)
Object.__init__(self)
# Now our vars
self.startTimeString = "" # The time when the timer starts as a string
self.endTimeString = "" # The time when the timer stops as a string
self.timeFormat = "" # The string to use as the format for the string
self.set = False # The timer starts deactivated
self.process = autotick # Wether or not to run in a seperate process.
self.rung = False # Has the timer rang yet?
# ACTIVATE --------------------------------------------------------------
# Sets the timer
def activate(self, startTime, endTime, format):
# Set the timer.
self.startTimeString = startTime
self.endTimeString = endTime
self.timeFormat = format
# Conver the strings to time using format
try:
self.startTime = time.strptime(startTime, self.timeFormat)
self.endTime = time.strptime(endTime, self.timeFormat)
except ValueError:
# Error
print ("Error: Cannot convert time according to format")
return False
# Try and convert the time to seconds
try:
self.startTimeSecs = time.mktime(self.startTime)
self.endTimeSecs = time.mktime(self.endTime)
except OverflowError, ValueError:
# Error
print ("Error: Cannot convert time to seconds")
return False
# The timer is now set
self.set = True
# If self.process is true, we need to start calling tick in a
# seperate process.
if self.process:
self.deamon = True # We don't want python to hang if a timer
# is still running at exit.
self.start()
# RING -------------------------------------------------------------
# This function is called when the timer starts.
def ring(self):
pass
# RUNNING ----------------------------------------------------------
# Called when the the time is whithin the time limits.
def running(self):
pass
# OVER -------------------------------------------------------------
# Called when the time is up
def over(self):
pass
# TICK -------------------------------------------------------------
# Call this every loop (or in a seperate process)
def tick(self):
print time.time(), self.startTimeSecs, self.endTimeSecs, time.strftime("%A %H:%M", time.localtime(self.startTimeSecs))
# Check the time
if time.mktime(time.localtime()) > self.startTimeSecs and time.mktime(time.localtime()) < self.endTimeSecs and not self.rung:
# The time has come =)
# Call ring()
self.ring()
# Now set self.rung to True
self.rung = True
# If the time is up..
elif time.mktime(time.localtime()) > self.endTimeSecs and self.rung:
self.over()
# Unset the timer
self.set = False
self.rung = False
# If we are inbetween the starttime and endtime.
elif time.mktime(time.localtime()) > self.startTimeSecs and time.mktime(time.localtime()) < self.endTimeSecs and self.rung:
self.running()
# If any of those aren't true, then the timer hasn't started yet
else:
# Check if the endTime has already passed
if time.mktime(time.localtime()) > self.endTimeSecs:
# The time has already passed.
self.set = False
# THREADING STUFF --------------------------------------------------
# This is run by Threads start() method.
def run(self):
while self.set == True:
# Tick
self.tick()
# Sleep for a bit to save CPU
time.sleep(settings.TIMER_SLEEP)
我还在一个调度器里添加了时间块:
# LOAD -------------------------------------------------------------
# Loads schedule from a file (schedule_settings.py).
def load(self):
# Add blocks
for block in schedule_settings.BLOCKS:
# Calculate the day
start_day = str(getDate(block[1].split()[0]))
end_day = str(getDate(block[2].split()[0]))
self.scheduler.add(start_day + " " + block[1].split()[1], end_day + " " + block[2].split()[1], "%j %H:%M", block[0])
for block in self.scheduler.blocks:
block.timer.tick()
print len(self.scheduler.blocks)
# Start the scheduler (if it isn't already)
if not self.scheduler.running:
self.scheduler.start()
添加功能看起来是这样的:
# ADD --------------------------------------------------------------
# Add a scheduled time
#
# block should be a Block instance, describing what to do at this time.
def add(self, startTime, endTime, format, block):
# Add this block
newBlock = block
# Start a timer for this block
newBlock.timer = Timer()
# Figure out the time
year = time.strftime("%Y")
# Add the block timer
newBlock.timer.activate(year + " " + startTime, year + " " + endTime, "%Y " + format)
# Add this block to the list
self.blocks.append(newBlock)
return
简单来说,我的程序可以让你制定一周的时间表,并像电视台一样播放视频。一个时间块就是一段时间,在这段时间里,频道会播放特定的剧集或系列。
我的问题是,使用添加功能后,这些时间块完全乱了。有些块被重复了,有些顺序错了等等。不过在使用添加功能之前,它们是完全正常的。如果我只用少量的时间块(2或3个),似乎就没问题。
举个例子,如果我的 schedule_settings.py(设置一周的时间表)看起来是这样的:
# -*- coding: utf-8 -*-
# This file contains settings for a week's schedule
from block import Block
from series import Series
# MAIN BLOCK (All old episodes)
mainBlock = Block()
mainBlock.picker = 'random'
mainBlock.name = "Main Block"
mainBlock.auto(".")
mainBlock.old_episodes = True
# ONE PIECE
onepieceBlock = Block()
onepieceBlock.picker = 'latest'
onepieceBlock.name = "One Piece"
onepieceBlock.series = [
Series(auto="One Piece"),
]
# NEWISH STUFF
newishBlock = Block()
newishBlock.picker = 'random'
newishBlock.auto(".")
newishBlock.name = "NewishBlock"
newishBlock.exclude_series = [
#Series(auto="One Piece"),
#Series(auto="Nyan Koi!"),
]
# NEW STUFF
newBlock = Block()
newBlock.picker = 'latest'
newBlock.name = "New Stuff"
newBlock.series = [
Series(auto="Nyan Koi!"),
]
# ACTIVE BLOCKS
BLOCKS = (
# MONDAY
(mainBlock, "Monday 08:00", "Monday 22:20"),
(onepieceBlock, "Monday 22:20", "Monday 22:30"),
(newishBlock, "Monday 22:30", "Monday 23:00"),
# TUESDAY
(mainBlock, "Tuesday 08:00", "Tuesday 18:00"),
(newBlock, "Tuesday 18:00", "Tuesday 18:30"),
(newishBlock, "Tuesday 18:30", "Tuesday 22:00"),
# WEDNESDAY
(mainBlock, "Wednesday 08:00", "Wednesday 18:00"),
(newBlock, "Wednesday 18:00", "Wednesday 18:30"),
(newishBlock, "Wednesday 18:30", "Wednesday 22:00"),
# THURSDAY
(mainBlock, "Thursday 08:00", "Thursday 18:00"),
(newBlock, "Thursday 18:00", "Thursday 18:30"),
(newishBlock, "Thursday 18:30", "Thursday 22:00"),
# FRIDAY
(mainBlock, "Friday 08:00", "Friday 18:00"),
(newBlock, "Friday 18:00", "Friday 18:30"),
# WEEKEND
(newishBlock, "Saturday 08:00", "Saturday 23:00"),
(newishBlock, "Sunday 08:00", "Sunday 23:00"),
)
在添加到调度器之前,生成的列表看起来很好,但在添加后再打印出来,我得到的是:
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1254777600.0 1254778200.0 Monday 22:20
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1255107600.0 1255109400.0 Friday 18:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1255107600.0 1255109400.0 Friday 18:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1255107600.0 1255109400.0 Friday 18:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255071600.0 1255107600.0 Friday 08:00
1254810368.0 1255107600.0 1255109400.0 Friday 18:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
1254810368.0 1255244400.0 1255298400.0 Sunday 08:00
我猜这可能和我在 Timer 类中对 threading.Thread 的子类化有关。把它通过一个函数传递并添加到列表中,会不会以某种方式搞乱了呢?
(编辑)抱歉,如果我说得不够清楚,我有点赶,忘了发最重要的代码 =( 用定时器手动滴答只是一些调试代码,正常情况下我会在定时器类中设置 auto=True。
你可以在这里找到我的所有代码:http://github.com/bombpersons/MYOT
2 个回答
唉,我现在觉得自己挺傻的。问题在于,块(block)是通过引用传递给调度器的,所以每次我在块里添加一个定时器的时候,实际上是在覆盖之前的定时器。
我创建了一个叫做schedulerBlock的类,里面包含了一个定时器和一个块。现在一切都正常运作了 =)
你给我们展示了很多代码,但关键部分没有,包括调度器的部分(还有那个奇怪的大写字母O的Object类是什么?)。不过,回答你的问题,传递线程子类的实例到函数里,或者把它们添加到列表中等等,这些都是完全可以的(虽然你做的其他事情可能就不太对了——比如,你可能不知道,虽然tick
是线程子类的方法,但从另一个线程调用它并不意味着它会在自己的线程中执行……实际上,它会在调用它的那个线程中执行)。
我建议你使用Python标准库中的sched模块来实现调度功能,而不是自己去写一个……