dcnum 0.25.2__tar.gz → 0.25.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dcnum might be problematic. Click here for more details.

Files changed (126) hide show
  1. {dcnum-0.25.2 → dcnum-0.25.4}/CHANGELOG +5 -0
  2. {dcnum-0.25.2 → dcnum-0.25.4}/PKG-INFO +1 -1
  3. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/_version.py +2 -2
  4. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_background/bg_roll_median.py +10 -0
  5. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_background/bg_sparse_median.py +10 -0
  6. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/queue_event_extractor.py +8 -0
  7. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/logic/ctrl.py +0 -27
  8. dcnum-0.25.4/src/dcnum/os_env_st.py +85 -0
  9. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/read/hdf5_data.py +5 -2
  10. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segmenter_mpo.py +10 -1
  11. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum.egg-info/PKG-INFO +1 -1
  12. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum.egg-info/SOURCES.txt +1 -0
  13. {dcnum-0.25.2 → dcnum-0.25.4}/tests/conftest.py +2 -5
  14. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_read_concat_hdf5.py +8 -2
  15. {dcnum-0.25.2 → dcnum-0.25.4}/.github/workflows/check.yml +0 -0
  16. {dcnum-0.25.2 → dcnum-0.25.4}/.github/workflows/deploy_pypi.yml +0 -0
  17. {dcnum-0.25.2 → dcnum-0.25.4}/.gitignore +0 -0
  18. {dcnum-0.25.2 → dcnum-0.25.4}/.readthedocs.yml +0 -0
  19. {dcnum-0.25.2 → dcnum-0.25.4}/LICENSE +0 -0
  20. {dcnum-0.25.2 → dcnum-0.25.4}/README.rst +0 -0
  21. {dcnum-0.25.2 → dcnum-0.25.4}/benchmark/.gitignore +0 -0
  22. {dcnum-0.25.2 → dcnum-0.25.4}/benchmark/Readme.md +0 -0
  23. {dcnum-0.25.2 → dcnum-0.25.4}/benchmark/benchmark.py +0 -0
  24. {dcnum-0.25.2 → dcnum-0.25.4}/benchmark/bm_write_deque_writer_thread.py +0 -0
  25. {dcnum-0.25.2 → dcnum-0.25.4}/benchmark/bm_write_queue_collector_thread.py +0 -0
  26. {dcnum-0.25.2 → dcnum-0.25.4}/docs/conf.py +0 -0
  27. {dcnum-0.25.2 → dcnum-0.25.4}/docs/extensions/github_changelog.py +0 -0
  28. {dcnum-0.25.2 → dcnum-0.25.4}/docs/index.rst +0 -0
  29. {dcnum-0.25.2 → dcnum-0.25.4}/docs/requirements.txt +0 -0
  30. {dcnum-0.25.2 → dcnum-0.25.4}/pyproject.toml +0 -0
  31. {dcnum-0.25.2 → dcnum-0.25.4}/setup.cfg +0 -0
  32. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/__init__.py +0 -0
  33. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/__init__.py +0 -0
  34. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/event_extractor_manager_thread.py +0 -0
  35. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_background/__init__.py +0 -0
  36. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_background/base.py +0 -0
  37. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_background/bg_copy.py +0 -0
  38. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_brightness/__init__.py +0 -0
  39. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_brightness/bright_all.py +0 -0
  40. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_brightness/common.py +0 -0
  41. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_contour/__init__.py +0 -0
  42. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_contour/contour.py +0 -0
  43. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_contour/moments.py +0 -0
  44. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_contour/volume.py +0 -0
  45. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_texture/__init__.py +0 -0
  46. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_texture/common.py +0 -0
  47. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/feat_texture/tex_all.py +0 -0
  48. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/feat/gate.py +0 -0
  49. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/logic/__init__.py +0 -0
  50. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/logic/job.py +0 -0
  51. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/logic/json_encoder.py +0 -0
  52. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/meta/__init__.py +0 -0
  53. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/meta/paths.py +0 -0
  54. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/meta/ppid.py +0 -0
  55. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/read/__init__.py +0 -0
  56. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/read/cache.py +0 -0
  57. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/read/const.py +0 -0
  58. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/read/detect_flicker.py +0 -0
  59. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/read/mapped.py +0 -0
  60. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/__init__.py +0 -0
  61. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segm_thresh.py +0 -0
  62. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segm_torch/__init__.py +0 -0
  63. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segm_torch/segm_torch_base.py +0 -0
  64. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segm_torch/segm_torch_mpo.py +0 -0
  65. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segm_torch/segm_torch_sto.py +0 -0
  66. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segm_torch/torch_model.py +0 -0
  67. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segm_torch/torch_postproc.py +0 -0
  68. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segm_torch/torch_preproc.py +0 -0
  69. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segmenter.py +0 -0
  70. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segmenter_manager_thread.py +0 -0
  71. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/segm/segmenter_sto.py +0 -0
  72. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/write/__init__.py +0 -0
  73. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/write/deque_writer_thread.py +0 -0
  74. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/write/queue_collector_thread.py +0 -0
  75. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum/write/writer.py +0 -0
  76. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum.egg-info/dependency_links.txt +0 -0
  77. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum.egg-info/requires.txt +0 -0
  78. {dcnum-0.25.2 → dcnum-0.25.4}/src/dcnum.egg-info/top_level.txt +0 -0
  79. {dcnum-0.25.2 → dcnum-0.25.4}/tests/data/fmt-hdf5_cytoshot_extended-moments-features.zip +0 -0
  80. {dcnum-0.25.2 → dcnum-0.25.4}/tests/data/fmt-hdf5_cytoshot_full-features_2023.zip +0 -0
  81. {dcnum-0.25.2 → dcnum-0.25.4}/tests/data/fmt-hdf5_cytoshot_full-features_2024.zip +0 -0
  82. {dcnum-0.25.2 → dcnum-0.25.4}/tests/data/fmt-hdf5_cytoshot_full-features_legacy_allev_2023.zip +0 -0
  83. {dcnum-0.25.2 → dcnum-0.25.4}/tests/data/fmt-hdf5_shapein_empty.zip +0 -0
  84. {dcnum-0.25.2 → dcnum-0.25.4}/tests/data/fmt-hdf5_shapein_raw-with-variable-length-logs.zip +0 -0
  85. {dcnum-0.25.2 → dcnum-0.25.4}/tests/data/segm-torch-model_unet-dcnum-test_g1_910c2.zip +0 -0
  86. {dcnum-0.25.2 → dcnum-0.25.4}/tests/data/segm-torch-test-data_unet-dcnum-test_g1_910c2.zip +0 -0
  87. {dcnum-0.25.2 → dcnum-0.25.4}/tests/helper_methods.py +0 -0
  88. {dcnum-0.25.2 → dcnum-0.25.4}/tests/requirements.txt +0 -0
  89. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_background_base.py +0 -0
  90. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_background_bg_copy.py +0 -0
  91. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_background_bg_roll_median.py +0 -0
  92. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_background_bg_sparsemed.py +0 -0
  93. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_brightness.py +0 -0
  94. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_event_extractor_manager.py +0 -0
  95. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_gate.py +0 -0
  96. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_haralick.py +0 -0
  97. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_moments_based.py +0 -0
  98. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_moments_based_extended.py +0 -0
  99. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_feat_volume.py +0 -0
  100. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_init.py +0 -0
  101. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_logic_job.py +0 -0
  102. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_logic_join.py +0 -0
  103. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_logic_json.py +0 -0
  104. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_logic_pipeline.py +0 -0
  105. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_meta_paths.py +0 -0
  106. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_meta_ppid_base.py +0 -0
  107. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_meta_ppid_bg.py +0 -0
  108. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_meta_ppid_data.py +0 -0
  109. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_meta_ppid_feat.py +0 -0
  110. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_meta_ppid_gate.py +0 -0
  111. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_meta_ppid_segm.py +0 -0
  112. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_read_basin.py +0 -0
  113. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_read_detect_flicker.py +0 -0
  114. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_read_hdf5.py +0 -0
  115. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_read_hdf5_basins.py +0 -0
  116. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_read_hdf5_index_mapping.py +0 -0
  117. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_segm_base.py +0 -0
  118. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_segm_mpo.py +0 -0
  119. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_segm_no_mask_proc.py +0 -0
  120. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_segm_sto.py +0 -0
  121. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_segm_thresh.py +0 -0
  122. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_segm_torch.py +0 -0
  123. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_segm_torch_preproc.py +0 -0
  124. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_write_deque_writer_thread.py +0 -0
  125. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_write_queue_collector_thread.py +0 -0
  126. {dcnum-0.25.2 → dcnum-0.25.4}/tests/test_write_writer.py +0 -0
@@ -1,3 +1,8 @@
1
+ 0.25.4
2
+ - enh: support passing a single file to `concatenated_hdf5_data`
3
+ 0.25.3
4
+ - enh: request single threaded operations when going into mp.Process (#17)
5
+ - enh: new module `dcnum.single_thread_osenv`
1
6
  0.25.2
2
7
  - setup: officially support numpy 2
3
8
  - setup: pin dependencies
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcnum
3
- Version: 0.25.2
3
+ Version: 0.25.4
4
4
  Summary: numerics toolbox for imaging deformability cytometry
5
5
  Author: Maximilian Schlögel, Paul Müller, Raghava Alajangi
6
6
  Maintainer-email: Paul Müller <dev@craban.de>
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.25.2'
16
- __version_tuple__ = version_tuple = (0, 25, 2)
15
+ __version__ = version = '0.25.4'
16
+ __version_tuple__ = version_tuple = (0, 25, 4)
@@ -4,6 +4,8 @@ import time
4
4
  import numpy as np
5
5
  from scipy import ndimage
6
6
 
7
+ from ...os_env_st import RequestSingleThreaded, confirm_single_threaded
8
+
7
9
  from .base import mp_spawn, Background
8
10
 
9
11
 
@@ -241,6 +243,8 @@ class WorkerRollMed(mp_spawn.Process):
241
243
 
242
244
  def run(self):
243
245
  """Main loop of worker process (breaks when `self.counter` <0)"""
246
+ # confirm single-threadedness (prints to log)
247
+ confirm_single_threaded()
244
248
  # Create the ctypes arrays here instead of during __init__, because
245
249
  # for some reason they are copied in __init__ and not mapped.
246
250
  shared_input = np.ctypeslib.as_array(
@@ -261,6 +265,12 @@ class WorkerRollMed(mp_spawn.Process):
261
265
  with self.counter.get_lock():
262
266
  self.counter.value += 1
263
267
 
268
+ def start(self):
269
+ # Set all relevant os environment variables such libraries in the
270
+ # new process only use single-threaded computation.
271
+ with RequestSingleThreaded():
272
+ mp_spawn.Process.start(self)
273
+
264
274
 
265
275
  def compute_median_for_slice(shared_input, shared_output, kernel_size,
266
276
  output_size, job_slice):
@@ -6,6 +6,8 @@ from scipy import ndimage
6
6
 
7
7
  from ...read import HDF5Data
8
8
 
9
+ from ...os_env_st import RequestSingleThreaded, confirm_single_threaded
10
+
9
11
  from .base import mp_spawn, Background
10
12
 
11
13
 
@@ -436,6 +438,8 @@ class WorkerSparseMed(mp_spawn.Process):
436
438
 
437
439
  def run(self):
438
440
  """Main loop of worker process (breaks when `self.counter` <0)"""
441
+ # confirm single-threadedness (prints to log)
442
+ confirm_single_threaded()
439
443
  # Create the ctypes arrays here instead of during __init__, because
440
444
  # for some reason they are copied in __init__ and not mapped.
441
445
  shared_input = np.ctypeslib.as_array(
@@ -468,3 +472,9 @@ class WorkerSparseMed(mp_spawn.Process):
468
472
  # overwrite_input=False)
469
473
  with self.counter.get_lock():
470
474
  self.counter.value += 1
475
+
476
+ def start(self):
477
+ # Set all relevant os environment variables such libraries in the
478
+ # new process only use single-threaded computation.
479
+ with RequestSingleThreaded():
480
+ mp_spawn.Process.start(self)
@@ -10,6 +10,7 @@ import traceback
10
10
 
11
11
  import numpy as np
12
12
 
13
+ from ..os_env_st import RequestSingleThreaded, confirm_single_threaded
13
14
  from ..meta.ppid import kwargs_to_ppid, ppid_to_kwargs
14
15
  from ..read import HDF5Data
15
16
 
@@ -325,6 +326,7 @@ class QueueEventExtractor:
325
326
 
326
327
  def run(self):
327
328
  """Main loop of worker process"""
329
+ confirm_single_threaded()
328
330
  self.worker_monitor[self.worker_index] = 0
329
331
  # Don't wait for these two queues when joining workers
330
332
  self.raw_queue.cancel_join_thread()
@@ -399,6 +401,12 @@ class EventExtractorProcess(QueueEventExtractor, mp_spawn.Process):
399
401
  super(EventExtractorProcess, self).__init__(
400
402
  name="EventExtractorProcess", *args, **kwargs)
401
403
 
404
+ def start(self):
405
+ # Set all relevant os environment variables such libraries in the
406
+ # new process only use single-threaded computation.
407
+ with RequestSingleThreaded():
408
+ mp_spawn.Process.start(self)
409
+
402
410
 
403
411
  class EventExtractorThread(QueueEventExtractor, threading.Thread):
404
412
  """Threading worker for debugging (only one single thread)"""
@@ -128,33 +128,6 @@ class DCNumJobRunner(threading.Thread):
128
128
 
129
129
  self.logger = logging.getLogger(f"dcnum.Runner-{self.pphash[:2]}")
130
130
 
131
- # Sanity checks
132
- for os_env in ["MKL_NUM_THREADS", "NUMBA_NUM_THREADS",
133
- "NUMEXPR_NUM_THREADS", "NUMPY_NUM_THREADS",
134
- "OPENBLAS_NUM_THREADS", "OMP_NUM_THREADS",
135
- "VECLIB_MAXIMUM_THREADS"]:
136
- # You should disable multithreading for all major tools that
137
- # use dcnum.logic. We don't want multithreading, because dcnum
138
- # uses linear code and relies on multiprocessing for
139
- # parallelization. This has to be done before importing numpy
140
- # or any other library affected. In your scripts, you can use:
141
- #
142
- # os.environ.setdefault("MKL_NUM_THREADS", "1")
143
- # os.environ.setdefault("NUMBA_NUM_THREADS", "1")
144
- # os.environ.setdefault("NUMEXPR_NUM_THREADS", "1")
145
- # os.environ.setdefault("NUMPY_NUM_THREADS", "1")
146
- # os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")
147
- # os.environ.setdefault("OMP_NUM_THREADS", "1")
148
- # os.environ.setdefault("VECLIB_MAXIMUM_THREADS", "1")
149
- #
150
- val_act = os.environ.get(os_env)
151
- if val_act != "1":
152
- self.logger.warning(
153
- f"Make sure to set the environment variable {os_env} to "
154
- f"'1' (disables multithreading)! Other values will reduce "
155
- f"performance and your system may become inresponsive. "
156
- f"The current value is '{val_act}'.")
157
-
158
131
  def __enter__(self):
159
132
  return self
160
133
 
@@ -0,0 +1,85 @@
1
+ import logging
2
+ import os
3
+
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ #: environment variables that set number of threads
8
+ os_env_threading = [
9
+ "MKL_NUM_THREADS",
10
+ "NUMBA_NUM_THREADS",
11
+ "NUMEXPR_NUM_THREADS",
12
+ "NUMPY_NUM_THREADS",
13
+ "OMP_NUM_THREADS",
14
+ "OPENBLAS_NUM_THREADS",
15
+ "VECLIB_MAXIMUM_THREADS",
16
+ ]
17
+
18
+
19
+ class RequestSingleThreaded:
20
+ """Context manager for starting a process with specific environment
21
+
22
+ When entering the context, the environment variables defined in
23
+ `os_env_threading` are all set to "1", telling the relevant libraries
24
+ that they should work in single-threaded mode.
25
+ When exiting the context, these environment variables are reset to
26
+ their original values (or unset if applicable).
27
+
28
+ Note that it makes only sense to use this context manager when
29
+ starting new multiprocessing processes. When the process spawns,
30
+ the environment from the current thread is copied. Setting the
31
+ environment variable after e.g. importing numpy has no effect
32
+ on how many threads numpy will use.
33
+ """
34
+ def __init__(self):
35
+ self.previous_env = {}
36
+
37
+ def __enter__(self):
38
+ """Ask nicely for single-threaded computation using `os.environ`
39
+
40
+ Note that this only affects new processes in which the
41
+ relevant libraries have not yet been imported.
42
+ """
43
+ for key in os_env_threading:
44
+ if key in os.environ:
45
+ self.previous_env[key] = os.environ[key]
46
+ os.environ[key] = "1"
47
+ return self
48
+
49
+ def __exit__(self, type, value, traceback):
50
+ """Restore the previous environment"""
51
+ for key in os_env_threading:
52
+ if key not in self.previous_env:
53
+ os.environ.pop(key)
54
+ else:
55
+ os.environ[key] = self.previous_env[key]
56
+
57
+
58
+ def confirm_single_threaded():
59
+ """Warn via logs when environment variables are not set to single thread"""
60
+ # Sanity checks
61
+ for os_env in os_env_threading:
62
+ # You should disable multithreading for all major tools that
63
+ # use dcnum.logic. We don't want multithreading, because dcnum
64
+ # uses linear code and relies on multiprocessing for
65
+ # parallelization. This has to be done before importing numpy
66
+ # or any other library affected. In your scripts, you can use:
67
+ #
68
+ val_act = os.environ.get(os_env)
69
+ if val_act != "1":
70
+ logger.warning(
71
+ f"Make sure to set the environment variable {os_env} to "
72
+ f"'1' (disables multithreading)! Other values will reduce "
73
+ f"performance and your system may become unresponsive. "
74
+ f"The current value is '{val_act}'.")
75
+
76
+
77
+ def request_single_threaded():
78
+ """Set the environment variable to single thread
79
+
80
+ This function must be called before importing the multithreaded
81
+ libraries (such as numpy) in order for them to pick up the
82
+ environment variables.
83
+ """
84
+ for key in os_env_threading:
85
+ os.environ[key] = "1"
@@ -593,8 +593,11 @@ def concatenated_hdf5_data(paths: List[pathlib.Path],
593
593
  raise ValueError(
594
594
  f"Invalid type for `path_out`: {type(path_out)} ({path_out}")
595
595
 
596
- if len(paths) <= 1:
597
- raise ValueError("Please specify at least two files in `paths`!")
596
+ if len(paths) == 0:
597
+ raise ValueError("Please specify at least one file in `paths`!")
598
+ elif len(paths) == 1:
599
+ warnings.warn("Only one file passed to `concatenated_hdf5_data`; this "
600
+ "is equivalent to using `HDF5Data`, but slower.")
598
601
 
599
602
  frames = []
600
603
 
@@ -7,6 +7,8 @@ from typing import Dict
7
7
  import numpy as np
8
8
  import scipy.ndimage as ndi
9
9
 
10
+ from ..os_env_st import RequestSingleThreaded, confirm_single_threaded
11
+
10
12
  from .segmenter import Segmenter
11
13
 
12
14
 
@@ -325,7 +327,8 @@ class MPOSegmenterWorker:
325
327
  self.sl_stop = sl_stop
326
328
 
327
329
  def run(self):
328
- # print(f"Running {self} in PID {os.getpid()}")
330
+ # confirm single-threadedness (prints to log)
331
+ confirm_single_threaded()
329
332
  # We have to create the numpy-versions of the mp.RawArrays here,
330
333
  # otherwise we only get some kind of copy in the new process
331
334
  # when we use "spawn" instead of "fork".
@@ -369,6 +372,12 @@ class MPOSegmenterWorkerProcess(MPOSegmenterWorker, mp_spawn.Process):
369
372
  def __init__(self, *args, **kwargs):
370
373
  super(MPOSegmenterWorkerProcess, self).__init__(*args, **kwargs)
371
374
 
375
+ def start(self):
376
+ # Set all relevant os environment variables such libraries in the
377
+ # new process only use single-threaded computation.
378
+ with RequestSingleThreaded():
379
+ mp_spawn.Process.start(self)
380
+
372
381
 
373
382
  class MPOSegmenterWorkerThread(MPOSegmenterWorker, threading.Thread):
374
383
  def __init__(self, *args, **kwargs):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcnum
3
- Version: 0.25.2
3
+ Version: 0.25.4
4
4
  Summary: numerics toolbox for imaging deformability cytometry
5
5
  Author: Maximilian Schlögel, Paul Müller, Raghava Alajangi
6
6
  Maintainer-email: Paul Müller <dev@craban.de>
@@ -17,6 +17,7 @@ docs/requirements.txt
17
17
  docs/extensions/github_changelog.py
18
18
  src/dcnum/__init__.py
19
19
  src/dcnum/_version.py
20
+ src/dcnum/os_env_st.py
20
21
  src/dcnum.egg-info/PKG-INFO
21
22
  src/dcnum.egg-info/SOURCES.txt
22
23
  src/dcnum.egg-info/dependency_links.txt
@@ -4,13 +4,10 @@ import shutil
4
4
  import tempfile
5
5
  import time
6
6
 
7
+ from dcnum.os_env_st import request_single_threaded
7
8
 
8
- # Make all libraries use only one single thread.
9
- os.environ.setdefault("OMP_NUM_THREADS", "1")
10
- os.environ.setdefault("MKL_NUM_THREADS", "1")
11
- os.environ.setdefault("NUMEXPR_NUM_THREADS", "1")
12
- os.environ.setdefault("NUMBA_NUM_THREADS", "1")
13
9
 
10
+ request_single_threaded()
14
11
 
15
12
  TMPDIR = tempfile.mkdtemp(prefix=time.strftime(
16
13
  "dcnum_test_%H.%M_"))
@@ -89,9 +89,15 @@ def test_concat_invalid_input_path():
89
89
 
90
90
 
91
91
  def test_concat_invalid_input_path_number():
92
+ with pytest.raises(ValueError, match="Please specify at least one"):
93
+ read.concatenated_hdf5_data([])
94
+
95
+
96
+ def test_concat_invalid_input_path_number_warn():
92
97
  path = retrieve_data("fmt-hdf5_cytoshot_full-features_2023.zip")
93
- with pytest.raises(ValueError, match="Please specify at least two"):
94
- read.concatenated_hdf5_data([path])
98
+ with pytest.warns(UserWarning, match="is equivalent to using"):
99
+ hd = read.concatenated_hdf5_data([path])
100
+ assert len(hd) == 40
95
101
 
96
102
 
97
103
  def test_concat_specify_input_feature_number():
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes