Commit a0c1ad3f authored by sumpfralle's avatar sumpfralle

simplified the code for multi-threading

multi-threading is now configurable via the commandline


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@727 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 9e09a2cb
...@@ -53,6 +53,8 @@ package repository list and run the following: ...@@ -53,6 +53,8 @@ package repository list and run the following:
apt-get install python-pyode python-opengl apt-get install python-pyode python-opengl
Afterwards you can remove the new package repository again. Afterwards you can remove the new package repository again.
Users of Python 2.5 with multiple CPU cores may want to install the package
"python-processing". This enables multi-threading for Python before v2.6.
MacOS MacOS
----- -----
......
...@@ -178,6 +178,11 @@ def execute(opts, args): ...@@ -178,6 +178,11 @@ def execute(opts, args):
else: else:
log.info("Psyco was disabled via the commandline") log.info("Psyco was disabled via the commandline")
# initialize multiprocessing
if not opts.parallel_processes is None:
import pycam.Utils.threading
pycam.Utils.threading.init_threading(opts.parallel_processes)
# initialize the progress bar # initialize the progress bar
progress_styles = {"none": pycam.Gui.Console.ConsoleProgressBar.STYLE_NONE, progress_styles = {"none": pycam.Gui.Console.ConsoleProgressBar.STYLE_NONE,
"text": pycam.Gui.Console.ConsoleProgressBar.STYLE_TEXT, "text": pycam.Gui.Console.ConsoleProgressBar.STYLE_TEXT,
...@@ -414,6 +419,11 @@ if __name__ == "__main__": ...@@ -414,6 +419,11 @@ if __name__ == "__main__":
group_general.add_option("", "--disable-psyco", dest="disable_psyco", group_general.add_option("", "--disable-psyco", dest="disable_psyco",
default=False, action="store_true", help="disable the Psyco " \ default=False, action="store_true", help="disable the Psyco " \
+ "just-in-time-compiler even when it is available") + "just-in-time-compiler even when it is available")
group_general.add_option("", "--number-of-processes",
dest="parallel_processes", default=None, type="int", action="store",
help="override the default detection of multiple CPU cores. " \
+ "Parallel processing only works with Python 2.6 or " \
+ "later.")
group_general.add_option("-q", "--quiet", dest="quiet", group_general.add_option("-q", "--quiet", dest="quiet",
default=False, action="store_true", help="show only warnings and " \ default=False, action="store_true", help="show only warnings and " \
+ "errors.") + "errors.")
......
...@@ -30,6 +30,7 @@ from pycam.PathGenerators import get_free_paths_ode, get_free_paths_triangles ...@@ -30,6 +30,7 @@ from pycam.PathGenerators import get_free_paths_ode, get_free_paths_triangles
from pycam.Geometry.utils import epsilon, ceil, sqrt from pycam.Geometry.utils import epsilon, ceil, sqrt
from pycam.Geometry import get_bisector, get_angle_pi from pycam.Geometry import get_bisector, get_angle_pi
from pycam.Utils import ProgressCounter from pycam.Utils import ProgressCounter
from pycam.Utils.threading import run_in_parallel
import pycam.Utils.log import pycam.Utils.log
import random import random
import math import math
...@@ -286,21 +287,9 @@ class ContourFollow: ...@@ -286,21 +287,9 @@ class ContourFollow:
projected_waterlines = [] projected_waterlines = []
triangles = self.model.triangles(minx=minx, miny=miny, maxx=maxx, triangles = self.model.triangles(minx=minx, miny=miny, maxx=maxx,
maxy=maxy) maxy=maxy)
try: results_iter = run_in_parallel(_process_one_triangle,
# try a multi-threading approach to use multiple CPUs [(self, t, z) for t in triangles], unordered=True)
import multiprocessing for result in results_iter:
# use the number of available CPUs
pool = multiprocessing.Pool()
results_it = pool.imap_unordered(_process_one_triangle,
[(self, t, z) for t in triangles])
except ImportError:
# use a single-threaded approach
def single_generator(triangles):
for t in triangles:
# an iterator is expected - thus we use a generator
yield _process_one_triangle((self, t, z))
results_it = single_generator(triangles)
for result in results_it:
for edge, shifted_edge in result: for edge, shifted_edge in result:
waterline_triangles.add(edge, shifted_edge) waterline_triangles.add(edge, shifted_edge)
if (not progress_counter is None) \ if (not progress_counter is None) \
......
# -*- coding: utf-8 -*-
"""
$Id$
Copyright 2010 Lars Kruse <devel@sumpfralle.de>
This file is part of PyCAM.
PyCAM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
PyCAM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with PyCAM. If not, see <http://www.gnu.org/licenses/>.
"""
import pycam.Utils.log
log = pycam.Utils.log.get_logger()
# possible values:
# None: not initialized
# False: no threading
# multiprocessing: the multiprocessing module is impored and enabled
__multiprocessing = None
# needs to be initialized, if multiprocessing is enabled
__num_of_processes = None
def init_threading(number_of_processes=None):
global __multiprocessing, __num_of_processes
try:
import multiprocessing
mp_is_available = True
except ImportError:
mp_is_available = False
if not mp_is_available:
__multiprocessing = False
else:
if number_of_processes is None:
# use defaults
# don't enable threading for a single cpu
if multiprocessing.cpu_count() > 1:
__multiprocessing = multiprocessing
__num_of_processes = multiprocessing.cpu_count()
else:
__multiprocessing = False
elif number_of_processes < 1:
__multiprocessing = False
else:
__multiprocessing = multiprocessing
__num_of_processes = number_of_processes
# send the configured state to the logger
if __multiprocessing is False:
log.info("Disabled multi-threading")
else:
log.info("Enabled multi-threading with %d parallel processes" % __num_of_processes)
def run_in_parallel(func, args, unordered=False):
global __multiprocessing, __num_of_processes
if __multiprocessing is None:
# threading was not configured before
init_threading()
if __multiprocessing:
# use the number of CPUs as the default number of worker threads
pool = __multiprocessing.Pool(__num_of_processes)
if unordered:
imap_func = pool.imap_unordered
else:
imap_func = pool.imap
# Beware: we may not return "pool.imap" or "pool.imap_unordered"
# directly. It would somehow loose the focus and just hang infinitely.
# Thus we wrap our own generator around it.
for result in imap_func(func, args):
yield result
else:
for arg in args:
yield func(arg)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment