0

render_inntertile & render_inntertile now called in batches in the worker process,

speeds up update scan with a lot of tiles to skip.
This commit is contained in:
Xon
2011-03-19 16:01:33 +08:00
parent 79d021279f
commit 2be64f2aa7

View File

@@ -292,10 +292,13 @@ class QuadtreeGen(object):
shutil.rmtree(getpath("3")) shutil.rmtree(getpath("3"))
os.rename(getpath("new3"), getpath("3")) os.rename(getpath("new3"), getpath("3"))
def _apply_render_worldtiles(self, pool): def _apply_render_worldtiles(self, pool,batch_size):
"""Returns an iterator over result objects. Each time a new result is """Returns an iterator over result objects. Each time a new result is
requested, a new task is added to the pool and a result returned. requested, a new task is added to the pool and a result returned.
""" """
batch = []
tiles = 0
for path in iterate_base4(self.p): for path in iterate_base4(self.p):
# Get the range for this tile # Get the range for this tile
colstart, rowstart = self._get_range_by_path(path) colstart, rowstart = self._get_range_by_path(path)
@@ -310,24 +313,42 @@ class QuadtreeGen(object):
tilechunks = self._get_chunks_in_range(colstart, colend, rowstart, tilechunks = self._get_chunks_in_range(colstart, colend, rowstart,
rowend) rowend)
#logging.debug(" tilechunks: %r", tilechunks) #logging.debug(" tilechunks: %r", tilechunks)
# Put this in the pool # Put this in the batch to be submited to the pool
# (even if tilechunks is empty, render_worldtile will delete # (even if tilechunks is empty, render_worldtile will delete
# existing images if appropriate) # existing images if appropriate)
yield pool.apply_async(func=render_worldtile, args= (self, batch.append((tilechunks, colstart, colend, rowstart, rowend, dest))
tilechunks, colstart, colend, rowstart, rowend, dest)) tiles += 1
if tiles >= batch_size:
tiles = 0
yield pool.apply_async(func=render_worldtile_batch, args= (self,batch))
batch = []
def _apply_render_inntertile(self, pool, zoom): if tiles > 0:
yield pool.apply_async(func=render_worldtile_batch, args= (self,batch))
def _apply_render_inntertile(self, pool, zoom,batch_size):
"""Same as _apply_render_worltiles but for the inntertile routine. """Same as _apply_render_worltiles but for the inntertile routine.
Returns an iterator that yields result objects from tasks that have Returns an iterator that yields result objects from tasks that have
been applied to the pool. been applied to the pool.
""" """
batch = []
tiles = 0
for path in iterate_base4(zoom): for path in iterate_base4(zoom):
# This image is rendered at: # This image is rendered at:
dest = os.path.join(self.destdir, self.tiledir, *(str(x) for x in path[:-1])) dest = os.path.join(self.destdir, self.tiledir, *(str(x) for x in path[:-1]))
name = str(path[-1]) name = str(path[-1])
yield pool.apply_async(func=render_innertile, args= (dest, name, self.imgformat, self.optimizeimg)) batch.append((dest, name, self.imgformat, self.optimizeimg))
tiles += 1
if tiles >= batch_size:
tiles = 0
yield pool.apply_async(func=render_innertile_batch, args= (batch))
batch = []
if tiles > 0:
yield pool.apply_async(func=render_innertile_batch, args= (batch))
def go(self, procs): def go(self, procs):
"""Renders all tiles""" """Renders all tiles"""
@@ -359,20 +380,21 @@ class QuadtreeGen(object):
logging.info("There are {0} total levels to render".format(self.p)) logging.info("There are {0} total levels to render".format(self.p))
logging.info("Don't worry, each level has only 25% as many tiles as the last.") logging.info("Don't worry, each level has only 25% as many tiles as the last.")
logging.info("The others will go faster") logging.info("The others will go faster")
for result in self._apply_render_worldtiles(pool): count = 0
batch_size = 50
for result in self._apply_render_worldtiles(pool,batch_size):
results.append(result) results.append(result)
if len(results) > 10000: if len(results) > (10000/batch_size):
# Empty the queue before adding any more, so that memory # Empty the queue before adding any more, so that memory
# required has an upper bound # required has an upper bound
while len(results) > 500: while len(results) > (500/batch_size):
results.popleft().get() complete += results.popleft().get()
complete += 1
self.print_statusline(complete, total, 1) self.print_statusline(complete, total, 1)
# Wait for the rest of the results # Wait for the rest of the results
while len(results) > 0: while len(results) > 0:
results.popleft().get()
complete += 1 complete += results.popleft().get()
self.print_statusline(complete, total, 1) self.print_statusline(complete, total, 1)
self.print_statusline(complete, total, 1, True) self.print_statusline(complete, total, 1, True)
@@ -384,17 +406,15 @@ class QuadtreeGen(object):
complete = 0 complete = 0
total = 4**zoom total = 4**zoom
logging.info("Starting level {0}".format(level)) logging.info("Starting level {0}".format(level))
for result in self._apply_render_inntertile(pool, zoom): for result in self._apply_render_inntertile(pool, zoom,batch_size):
results.append(result) results.append(result)
if len(results) > 10000: if len(results) > (10000/batch_size):
while len(results) > 500: while len(results) > (500/batch_size):
results.popleft().get() complete += results.popleft().get()
complete += 1
self.print_statusline(complete, total, level) self.print_statusline(complete, total, level)
# Empty the queue # Empty the queue
while len(results) > 0: while len(results) > 0:
results.popleft().get() complete += results.popleft().get()
complete += 1
self.print_statusline(complete, total, level) self.print_statusline(complete, total, level)
self.print_statusline(complete, total, level, True) self.print_statusline(complete, total, level, True)
@@ -448,6 +468,14 @@ class QuadtreeGen(object):
return chunklist return chunklist
@catch_keyboardinterrupt @catch_keyboardinterrupt
def render_innertile_batch( batch):
count = 0
#logging.debug("{0} working on batch of size {1}".format(os.getpid(),len(batch)))
for job in batch:
count += 1
render_worldtile(job[0],job[1],job[2],job[3])
return count
def render_innertile(dest, name, imgformat, optimizeimg): def render_innertile(dest, name, imgformat, optimizeimg):
""" """
Renders a tile at os.path.join(dest, name)+".ext" by taking tiles from Renders a tile at os.path.join(dest, name)+".ext" by taking tiles from
@@ -512,6 +540,14 @@ def render_innertile(dest, name, imgformat, optimizeimg):
optimize_image(imgpath, imgformat, optimizeimg) optimize_image(imgpath, imgformat, optimizeimg)
@catch_keyboardinterrupt @catch_keyboardinterrupt
def render_worldtile_batch(quadtree, batch):
count = 0
#logging.debug("{0} working on batch of size {1}".format(os.getpid(),len(batch)))
for job in batch:
count += 1
render_worldtile(quadtree,job[0],job[1],job[2],job[3],job[4],job[5])
return count
def render_worldtile(quadtree, chunks, colstart, colend, rowstart, rowend, path): def render_worldtile(quadtree, chunks, colstart, colend, rowstart, rowend, path):
"""Renders just the specified chunks into a tile and save it. Unlike usual """Renders just the specified chunks into a tile and save it. Unlike usual
python conventions, rowend and colend are inclusive. Additionally, the python conventions, rowend and colend are inclusive. Additionally, the
@@ -529,7 +565,7 @@ def render_worldtile(quadtree, chunks, colstart, colend, rowstart, rowend, path)
Standard tile size has colend-colstart=2 and rowend-rowstart=4 Standard tile size has colend-colstart=2 and rowend-rowstart=4
There is no return value There is no return value
""" """
# width of one chunk is 384. Each column is half a chunk wide. The total # width of one chunk is 384. Each column is half a chunk wide. The total
# width is (384 + 192*(numcols-1)) since the first column contributes full # width is (384 + 192*(numcols-1)) since the first column contributes full