0

get genpoi multiprocessing working on windows

This commit is contained in:
Aaron Griffith
2015-03-12 12:21:39 -04:00
parent cc3bee821c
commit 88de7b1567

View File

@@ -32,7 +32,6 @@ from optparse import OptionParser
from overviewer_core import logger from overviewer_core import logger
from overviewer_core import nbt from overviewer_core import nbt
from overviewer_core import configParser, world from overviewer_core import configParser, world
from overviewer_core import rendermodes
UUID_LOOKUP_URL = 'https://sessionserver.mojang.com/session/minecraft/profile/' UUID_LOOKUP_URL = 'https://sessionserver.mojang.com/session/minecraft/profile/'
@@ -85,11 +84,27 @@ def jsonText(s):
else: else:
return s return s
# Since functions are not pickleable, we send their names instead.
# Here, set up worker processes to have a name -> function map
bucketChunkFuncs = {}
def initBucketChunks(config_path):
global bucketChunkFuncs
mw_parser = configParser.MultiWorldParser()
mw_parser.parse(config_path)
# ought not to fail since we already did it once
config = mw_parser.get_validated_config()
for name, render in config['renders'].iteritems():
for f in render['markers']:
ff = f['filterFunction']
bucketChunkFuncs[ff.__name__] == ff
# yes there's a double parenthesis here # yes there's a double parenthesis here
# see below for when this is called, and why we do this # see below for when this is called, and why we do this
# a smarter way would be functools.partial, but that's broken on python 2.6 # a smarter way would be functools.partial, but that's broken on python 2.6
# when used with multiprocessing # when used with multiprocessing
def parseBucketChunks((bucket, rset, filters)): def parseBucketChunks((bucket, rset, filters)):
global bucketChunkFuncs
pid = multiprocessing.current_process().pid pid = multiprocessing.current_process().pid
markers = defaultdict(list) markers = defaultdict(list)
@@ -102,7 +117,8 @@ def parseBucketChunks((bucket, rset, filters)):
if poi['id'] == 'Sign': if poi['id'] == 'Sign':
poi = signWrangler(poi) poi = signWrangler(poi)
for name, filter_function in filters: for name, filter_function in filters:
result = filter_function(poi) ff = bucketChunkFuncs[filter_function]
result = ff(poi)
if result: if result:
d = create_marker_from_filter_result(poi, result) d = create_marker_from_filter_result(poi, result)
markers[name].append(d) markers[name].append(d)
@@ -127,7 +143,7 @@ def signWrangler(poi):
return poi return poi
def handleEntities(rset, config, filters, markers): def handleEntities(rset, config, config_path, filters, markers):
""" """
Add markers for Entities or TileEntities. Add markers for Entities or TileEntities.
@@ -169,10 +185,10 @@ def handleEntities(rset, config, filters, markers):
logging.info("Buckets has %d entries", len(b)); logging.info("Buckets has %d entries", len(b));
# Create a pool of processes and run all the functions # Create a pool of processes and run all the functions
pool = Pool(processes=numbuckets) pool = Pool(processes=numbuckets, initializer=initBucketChunks, initargs=(config_path,))
# simplify the filters dict, so pickle doesn't have to do so much # simplify the filters dict, so pickle doesn't have to do so much
filters = [(name, filter_function) for name, __, filter_function, __, __, __ in filters] filters = [(name, filter_function.__name__) for name, __, filter_function, __, __, __ in filters]
results = pool.map(parseBucketChunks, ((buck, rset, filters) for buck in buckets)) results = pool.map(parseBucketChunks, ((buck, rset, filters) for buck in buckets))
@@ -452,17 +468,6 @@ def main():
# internal identifier for this filter # internal identifier for this filter
name = replaceBads(f['name']) + hex(hash(f['filterFunction']))[-4:] + "_" + hex(hash(rset))[-4:] name = replaceBads(f['name']) + hex(hash(f['filterFunction']))[-4:] + "_" + hex(hash(rset))[-4:]
# we need to make the function pickleable for multiprocessing to
# work
# We set a custom prefix here to not override any functions there.
# These functions are only pickleable if they are bound to a
# module. Since rendermodes imports the config, they are bound to
# it anyway, but don't end up importable as
# `rendermodes.filter_fn`. That's why we set it here explicitly on
# the module.
f['filterFunction'].__name__ = "custom_filter_" + f['filterFunction'].__name__
setattr(rendermodes, f['filterFunction'].__name__, f['filterFunction'])
# add it to the list of filters # add it to the list of filters
filters.add((name, f['name'], f['filterFunction'], rset, worldpath, rname)) filters.add((name, f['name'], f['filterFunction'], rset, worldpath, rname))
@@ -484,7 +489,7 @@ def main():
keyfunc = lambda x: x[3] keyfunc = lambda x: x[3]
sfilters = sorted(filters, key=keyfunc) sfilters = sorted(filters, key=keyfunc)
for rset, rset_filters in itertools.groupby(sfilters, keyfunc): for rset, rset_filters in itertools.groupby(sfilters, keyfunc):
handleEntities(rset, config, rset_filters, markers) handleEntities(rset, config, options.config, rset_filters, markers)
# apply filters to players # apply filters to players
if not options.skipplayers: if not options.skipplayers: