handle job never returning Job.Done, allow yield None instead of yield Job.Continue, added suspend/resume

This commit is contained in:
Darren Ranalli 2007-03-10 13:05:09 +00:00
parent 89b2d71e56
commit ac9c7274f6
2 changed files with 37 additions and 15 deletions

View File

@ -1,8 +1,11 @@
class Job:
# Base class for cpu-intensive or non-time-critical operations that
# are run through the JobManager.
# values to yield from your run() generator method
Done = object()
Continue = object()
Continue = None # 'yield None' is acceptable in place of 'yield Job.Continue'
Priorities = ScratchPad(Low=-100, Normal=0, High=100)
_SerialGen = SerialNumGen()
@ -15,16 +18,26 @@ class Job:
del self._name
del self._generator
def run(self):
# override and do your processing
# yield Job.Continue when possible/reasonable
# try not to run longer than the JobManager's timeslice between yields
# when done, yield Job.Done
raise "don't call down"
def getPriority(self):
# override if you want a different priority
# you can use numbers other than those in Job.Priorities
return Job.Priorities.Normal
def run(self):
# override and yield Job.Continue when possible/reasonable
# try not to run longer than the JobManager's timeslice between yields
# when done, yield Job.Done
raise "don't call down"
def suspend(self):
# called when JobManager is going to stop running this job for a while
# most jobs don't need to override this
pass
def resume(self):
# called when JobManager is going to start running this job again
# most jobs don't need to override this
pass
def _getJobId(self):
return self._id
@ -48,7 +61,7 @@ if __debug__: # __dev__ not yet available at this point
while self._accum < 100:
self._accum += 1
print 'counter = %s, accum = %s' % (self._counter, self._accum)
yield Job.Continue
yield None
self._accum = 0
self._counter += 1
@ -57,9 +70,7 @@ if __debug__: # __dev__ not yet available at this point
print 'Job.Done'
yield Job.Done
else:
yield Job.Continue
yield None
def addTestJob():
t = TestJob()
jobMgr.add(t)
jobMgr.add(TestJob())

View File

@ -6,11 +6,11 @@ class JobManager:
"""
Similar to the taskMgr but designed for tasks that are CPU-intensive and/or
not time-critical. Jobs run one at a time, in order of priority, in
the timeslice that the JobManager is allowed to run each frame.
the timeslice that the JobManager is allotted each frame.
"""
notify = directNotify.newCategory("JobManager")
# there's one main task for the JobManager, all jobs run in this task
# there's one task for the JobManager, all jobs run in this task
TaskName = 'jobManager'
# run for one millisecond per frame by default
DefTimeslice = .001
@ -85,14 +85,24 @@ class JobManager:
endT = globalClock.getRealTime() + (self._timeslice * .9)
while True:
# always process the highest priority first
# TODO: give occasional timeslices to lower priorities to avoid starving
# lower-priority jobs
jobId2job = self._pri2jobId2job[self._highestPriority]
# process jobs with equal priority in the order they came in
jobId = self._pri2jobIds[self._highestPriority][-1]
job = jobId2job[jobId]
gen = job._getGenerator()
job.resume()
while globalClock.getRealTime() < endT:
result = gen.next()
try:
result = gen.next()
except StopIteration:
# Job didn't yield Job.Done, it ran off the end and returned
# treat it as if it returned Job.Done
self.notify.warning('job %s never yielded Job.Done' % job)
result = Job.Done
if result is Job.Done:
job.suspend()
self.remove(job)
# highest-priority job is done.
# grab the next one if there's time left
@ -100,9 +110,10 @@ class JobManager:
else:
# we've run out of time
assert self.notify.debug('out of time: %s, %s' % (endT, globalClock.getRealTime()))
job.suspend()
break
if len(self._pri2jobId2job) == 0:
# there's nothing left to do
# there's nothing left to do, all the jobs are done!
break
return task.cont