Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use num_workers instead of alternate parameter names #7302

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions benchmarks/benchmark_restoration.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,11 @@ def time_rollingball_ndim(self):

time_rollingball_ndim.setup = _skip_slow

def time_rollingball_threads(self, threads):
restoration.rolling_ball(data.coins(), radius=100, num_threads=threads)
def time_rollingball_parallel(self, num_workers):
restoration.rolling_ball(data.coins(), radius=100, num_workers=num_workers)

time_rollingball_threads.params = (0, 2, 4, 8)
time_rollingball_threads.param_names = ["threads"]
time_rollingball_parallel.params = (0, 2, 4, 8)
time_rollingball_parallel.param_names = ["num_workers"]


class Inpaint:
Expand Down
8 changes: 4 additions & 4 deletions skimage/_shared/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,15 +321,15 @@ def fetch(data_filename):
pytest.skip(f'Unable to download {data_filename}', allow_module_level=True)


def run_in_parallel(num_threads=2, warnings_matching=None):
def run_in_parallel(num_workers=2, warnings_matching=None):
"""Decorator to run the same function multiple times in parallel.

This decorator is useful to ensure that separate threads execute
concurrently and correctly while releasing the GIL.

Parameters
----------
num_threads : int, optional
num_workers : int, optional
The number of times the function is run in parallel.

warnings_matching: list or None
Expand All @@ -340,14 +340,14 @@ def run_in_parallel(num_threads=2, warnings_matching=None):

"""

assert num_threads > 0
assert num_workers > 0

def wrapper(func):
@functools.wraps(func)
def inner(*args, **kwargs):
with expected_warnings(warnings_matching):
threads = []
for i in range(num_threads - 1):
for i in range(num_workers - 1):
thread = threading.Thread(target=func, args=args, kwargs=kwargs)
threads.append(thread)
for thread in threads:
Expand Down
4 changes: 2 additions & 2 deletions skimage/_shared/tests/test_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ def change_state1():
change_state1()
assert len(state) == 2

@run_in_parallel(num_threads=1)
@run_in_parallel(num_workers=1)
def change_state2():
state.append(None)

change_state2()
assert len(state) == 3

@run_in_parallel(num_threads=3)
@run_in_parallel(num_workers=3)
def change_state3():
state.append(None)

Expand Down
27 changes: 21 additions & 6 deletions skimage/restoration/_rolling_ball.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import numpy as np

from .._shared.utils import _supported_float_type
from .._shared.utils import _supported_float_type, deprecate_parameter, DEPRECATED
from ._rolling_ball_cy import apply_kernel, apply_kernel_nan


def rolling_ball(image, *, radius=100, kernel=None, nansafe=False, num_threads=None):
@deprecate_parameter(
"num_threads", new_name="num_workers", start_version="0.23", stop_version="0.26"
lagru marked this conversation as resolved.
Show resolved Hide resolved
)
def rolling_ball(
image,
*,
radius=100,
kernel=None,
nansafe=False,
num_threads=DEPRECATED,
num_workers=None,
):
"""Estimate background intensity by rolling/translating a kernel.

This rolling ball algorithm estimates background intensity for a
Expand All @@ -25,12 +36,16 @@ def rolling_ball(image, *, radius=100, kernel=None, nansafe=False, num_threads=N
nansafe: bool, optional
If ``False`` (default) assumes that none of the values in ``image``
are ``np.nan``, and uses a faster implementation.
num_threads: int, optional
num_workers: int, optional
The maximum number of threads to use. If ``None`` use the OpenMP
default value; typically equal to the maximum number of virtual cores.
Note: This is an upper limit to the number of threads. The exact number
is determined by the system's OpenMP library.

.. versionchanged:: 0.23

Replaced old parameter `num_threads` in 0.23.

Returns
-------
background : ndarray
Expand Down Expand Up @@ -81,8 +96,8 @@ def rolling_ball(image, *, radius=100, kernel=None, nansafe=False, num_threads=N
float_type = _supported_float_type(image.dtype)
img = image.astype(float_type, copy=False)

if num_threads is None:
num_threads = 0
if num_workers is None:
num_workers = 0

if kernel is None:
kernel = ball_kernel(radius, image.ndim)
Expand All @@ -109,7 +124,7 @@ def rolling_ball(image, *, radius=100, kernel=None, nansafe=False, num_threads=N
np.array(image.shape, dtype=np.intp),
np.array(img.shape, dtype=np.intp),
kernel_shape.astype(np.intp),
num_threads,
num_workers,
)

background = background.astype(image.dtype, copy=False)
Expand Down
12 changes: 6 additions & 6 deletions skimage/restoration/_rolling_ball_cy.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def apply_kernel_nan(DTYPE_FLOAT[::1] img not None,
Py_ssize_t[::1] img_shape not None,
Py_ssize_t[::1] padded_img_shape not None,
Py_ssize_t[::1] kernel_shape not None,
Py_ssize_t num_threads=0):
Py_ssize_t num_workers=0):
"""Apply a ND kernel to an ND image.

This function is the critical piece of code for
Expand All @@ -103,7 +103,7 @@ def apply_kernel_nan(DTYPE_FLOAT[::1] img not None,
The shape of the unflattened, padded image.
kernel_shape : (N) ndarray
The shape of the unflattened kernel.
num_threads : int, optional
num_workers : int, optional
The number of threads used to compute the result. If no value is
provided (0, default) fall back to the number of threads that openMP
is currently configured to use.
Expand Down Expand Up @@ -131,7 +131,7 @@ def apply_kernel_nan(DTYPE_FLOAT[::1] img not None,

for offset_idx in prange(
out_data_size,
num_threads=num_threads,
num_threads=num_workers,
nogil=True):
offset = ind2ind(offset_idx, 0, img_shape, padded_img_shape)
min_value = INFINITY
Expand Down Expand Up @@ -162,7 +162,7 @@ def apply_kernel(DTYPE_FLOAT[::1] img not None,
Py_ssize_t[::1] img_shape not None,
Py_ssize_t[::1] padded_img_shape not None,
Py_ssize_t[::1] kernel_shape not None,
Py_ssize_t num_threads=0):
Py_ssize_t num_workers=0):
"""Apply a ND kernel to an ND image.

This function is the critical piece of code for
Expand All @@ -187,7 +187,7 @@ def apply_kernel(DTYPE_FLOAT[::1] img not None,
The shape of the unflattened, padded image.
kernel_shape : (N) ndarray
The shape of the unflattened kernel.
num_threads : int, optional
num_workers : int, optional
The number of threads used to compute the result. If no value is
provided (0, default) fall back to the number of threads that openMP
is currently configured to use.
Expand Down Expand Up @@ -220,7 +220,7 @@ def apply_kernel(DTYPE_FLOAT[::1] img not None,

for offset_idx in prange(
out_data_size,
num_threads=num_threads,
num_threads=num_workers,
nogil=True):
offset = ind2ind(offset_idx, 0, img_shape, padded_img_shape)
min_value = INFINITY
Expand Down
21 changes: 17 additions & 4 deletions skimage/restoration/tests/test_rolling_ball.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
(skimage.restoration.rolling_ball)
"""

import inspect

import numpy as np
import pytest

Expand Down Expand Up @@ -81,16 +83,27 @@ def test_preserve_peaks(radius):
assert np.allclose(img - background, expected_img)


@pytest.mark.parametrize("num_threads", [None, 1, 2])
def test_threads(num_threads):
@pytest.mark.parametrize("num_workers", [None, 1, 2])
def test_workers(num_workers):
# not testing if we use multiple threads
# just checking if the API throws an exception
img = 23 * np.ones((100, 100), dtype=np.uint8)
rolling_ball(img, radius=10, num_threads=num_threads)
rolling_ball(img, radius=10, nansafe=True, num_threads=num_threads)
rolling_ball(img, radius=10, num_workers=num_workers)
rolling_ball(img, radius=10, nansafe=True, num_workers=num_workers)


def test_ndim():
image = data.cells3d()[:5, 1, ...]
kernel = ellipsoid_kernel((3, 100, 100), 100)
rolling_ball(image, kernel=kernel)


@pytest.mark.parametrize("num_threads", [None, 1, 2])
def test_deprecated_num_threads(num_threads):
img = 23 * np.ones((100, 100), dtype=np.uint8)
with pytest.warns(FutureWarning, match=".*`num_threads` is deprecated") as record:
rolling_ball(img, radius=10, num_threads=num_threads)
lineno = inspect.currentframe().f_lineno - 1
assert len(record) == 1
assert record[0].filename == __file__
assert record[0].lineno == lineno