7
7
import multiprocessing
8
8
import os
9
9
import os .path
10
+ import sys
10
11
import threading
11
12
import time
13
+ import warnings
12
14
13
15
import humanfriendly
14
16
import numcodecs
@@ -87,6 +89,11 @@ def du(path):
87
89
88
90
89
91
class SynchronousExecutor (cf .Executor ):
92
+ # Arguably we should use workers=0 as the default and use this
93
+ # executor implementation. However, the docs are fairly explicit
94
+ # about saying we shouldn't instantiate Future objects directly,
95
+ # so it's best to keep this as a semi-secret debugging interface
96
+ # for now.
90
97
def submit (self , fn , / , * args , ** kwargs ):
91
98
future = cf .Future ()
92
99
future .set_result (fn (* args , ** kwargs ))
@@ -215,6 +222,22 @@ def setup_progress_counter(counter):
215
222
_progress_counter = counter
216
223
217
224
225
+ def warn_py39_mac ():
226
+ if sys .platform == "darwin" and sys .version_info [:2 ] == (3 , 9 ):
227
+ warnings .warn (
228
+ "There is a known issue with bio2zarr on MacOS Python 3.9 "
229
+ "in which OS-level named semaphores are leaked. "
230
+ "You will also probably see warnings like 'There appear to be N "
231
+ "leaked semaphore objects at shutdown'. "
232
+ "While this is likely harmless for a few runs, it could lead to "
233
+ "issues if you do a lot of conversion. To get prevent this issue "
234
+ "either: (1) use --worker-processes=0 or (2) upgrade to a newer "
235
+ "Python version. See https://github.com/sgkit-dev/bio2zarr/issues/209 "
236
+ "for more details." ,
237
+ stacklevel = 2 ,
238
+ )
239
+
240
+
218
241
class ParallelWorkManager (contextlib .AbstractContextManager ):
219
242
def __init__ (self , worker_processes = 1 , progress_config = None ):
220
243
# Need to specify this explicitly to suppport Macs and
@@ -223,9 +246,11 @@ def __init__(self, worker_processes=1, progress_config=None):
223
246
global _progress_counter
224
247
_progress_counter = ctx .Value ("Q" , 0 )
225
248
if worker_processes <= 0 :
226
- # NOTE: this is only for testing, not for production use!
249
+ # NOTE: this is only for testing and debugging, not for
250
+ # production. See note on the SynchronousExecutor class.
227
251
self .executor = SynchronousExecutor ()
228
252
else :
253
+ warn_py39_mac ()
229
254
self .executor = cf .ProcessPoolExecutor (
230
255
max_workers = worker_processes ,
231
256
mp_context = ctx ,
0 commit comments