Parallelize now reseeds random number generators after fork()

Bugfix -- AxisItem enforces tick boundaries more strictly
This commit is contained in:
Luke Campagnola 2012-06-30 23:32:26 -04:00
parent 3d71a1f555
commit 73e94f543c
2 changed files with 36 additions and 5 deletions

View File

@ -537,6 +537,10 @@ class AxisItem(GraphicsWidget):
else: else:
xScale = bounds.width() / dif xScale = bounds.width() / dif
offset = self.range[0] * xScale offset = self.range[0] * xScale
xRange = [x * xScale - offset for x in self.range]
xMin = min(xRange)
xMax = max(xRange)
prof.mark('init') prof.mark('init')
@ -545,6 +549,7 @@ class AxisItem(GraphicsWidget):
## draw ticks ## draw ticks
## (to improve performance, we do not interleave line and text drawing, since this causes unnecessary pipeline switching) ## (to improve performance, we do not interleave line and text drawing, since this causes unnecessary pipeline switching)
## draw three different intervals, long ticks first ## draw three different intervals, long ticks first
for i in range(len(tickLevels)): for i in range(len(tickLevels)):
tickPositions.append([]) tickPositions.append([])
ticks = tickLevels[i][1] ticks = tickLevels[i][1]
@ -557,7 +562,13 @@ class AxisItem(GraphicsWidget):
lineAlpha = self.grid lineAlpha = self.grid
for v in ticks: for v in ticks:
## determine actual position to draw this tick
x = (v * xScale) - offset x = (v * xScale) - offset
if x < xMin or x > xMax: ## last check to make sure no out-of-bounds ticks are drawn
tickPositions[i].append(None)
continue
tickPositions[i].append(x)
p1 = [x, x] p1 = [x, x]
p2 = [x, x] p2 = [x, x]
p1[axis] = tickStart p1[axis] = tickStart
@ -570,7 +581,6 @@ class AxisItem(GraphicsWidget):
tickPen.setColor(color) tickPen.setColor(color)
p.setPen(tickPen) p.setPen(tickPen)
p.drawLine(Point(p1), Point(p2)) p.drawLine(Point(p1), Point(p2))
tickPositions[i].append(x)
prof.mark('draw ticks') prof.mark('draw ticks')
## Draw text until there is no more room (or no more text) ## Draw text until there is no more room (or no more text)
@ -585,10 +595,15 @@ class AxisItem(GraphicsWidget):
if len(strings) == 0: if len(strings) == 0:
continue continue
## ignore strings belonging to ticks that were previously ignored
for j in range(len(strings)):
if tickPositions[i][j] is None:
strings[j] = None
if i > 0: ## always draw top level if i > 0: ## always draw top level
## measure all text, make sure there's enough room ## measure all text, make sure there's enough room
textRects.extend([p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, s) for s in strings]) textRects.extend([p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, s) for s in strings if s is not None])
if axis == 0: if axis == 0:
textSize = np.sum([r.height() for r in textRects]) textSize = np.sum([r.height() for r in textRects])
else: else:
@ -603,6 +618,8 @@ class AxisItem(GraphicsWidget):
#strings = self.tickStrings(values, self.scale, spacing) #strings = self.tickStrings(values, self.scale, spacing)
for j in range(len(strings)): for j in range(len(strings)):
vstr = strings[j] vstr = strings[j]
if vstr is None:## this tick was ignored because it is out of bounds
continue
x = tickPositions[i][j] x = tickPositions[i][j]
textRect = p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, vstr) textRect = p.boundingRect(QtCore.QRectF(0, 0, 100, 100), QtCore.Qt.AlignCenter, vstr)
height = textRect.height() height = textRect.height()

View File

@ -37,7 +37,7 @@ class Parallelize:
since it is automatically sent via pipe back to the parent process. since it is automatically sent via pipe back to the parent process.
""" """
def __init__(self, tasks, workers=None, block=True, progressDialog=None, **kwds): def __init__(self, tasks, workers=None, block=True, progressDialog=None, randomReseed=True, **kwds):
""" """
=============== =================================================================== =============== ===================================================================
Arguments: Arguments:
@ -47,6 +47,9 @@ class Parallelize:
system system
progressDialog optional dict of arguments for ProgressDialog progressDialog optional dict of arguments for ProgressDialog
to update while tasks are processed to update while tasks are processed
randomReseed If True, each forked process will reseed its random number generator
to ensure independent results. Works with the built-in random
and numpy.random.
kwds objects to be shared by proxy with child processes (they will kwds objects to be shared by proxy with child processes (they will
appear as attributes of the tasker) appear as attributes of the tasker)
=============== =================================================================== =============== ===================================================================
@ -68,6 +71,7 @@ class Parallelize:
workers = 1 workers = 1
self.workers = workers self.workers = workers
self.tasks = list(tasks) self.tasks = list(tasks)
self.reseed = randomReseed
self.kwds = kwds.copy() self.kwds = kwds.copy()
self.kwds['_taskStarted'] = self._taskStarted self.kwds['_taskStarted'] = self._taskStarted
@ -112,7 +116,7 @@ class Parallelize:
## fork and assign tasks to each worker ## fork and assign tasks to each worker
for i in range(workers): for i in range(workers):
proc = ForkedProcess(target=None, preProxy=self.kwds) proc = ForkedProcess(target=None, preProxy=self.kwds, randomReseed=self.reseed)
if not proc.isParent: if not proc.isParent:
self.proc = proc self.proc = proc
return Tasker(proc, chunks[i], proc.forkedProxies) return Tasker(proc, chunks[i], proc.forkedProxies)
@ -150,7 +154,17 @@ class Parallelize:
#print "remove:", [ch.childPid for ch in rem] #print "remove:", [ch.childPid for ch in rem]
for ch in rem: for ch in rem:
activeChilds.remove(ch) activeChilds.remove(ch)
os.waitpid(ch.childPid, 0) while True:
try:
os.waitpid(ch.childPid, 0)
break
except OSError as ex:
if ex.errno == 4: ## If we get this error, just try again
continue
#print "Ignored system call interruption"
else:
raise
#print [ch.childPid for ch in activeChilds] #print [ch.childPid for ch in activeChilds]
if self.showProgress and self.progressDlg.wasCanceled(): if self.showProgress and self.progressDlg.wasCanceled():