1717import itertools
1818import os
1919import queue
20+ import sys
2021import threading
2122import time
2223import traceback
@@ -175,6 +176,10 @@ class Pool(object):
175176 Class which supports an async version of applying functions to arguments.
176177 '''
177178 _wrap_exception = True
179+ # On Windows, WaitForMultipleObjects is used to wait for processes to
180+ # finish. It can wait on, at most, 64 objects. There is an overhead of three
181+ # objects.
182+ _MAX_WINDOWS_WORKERS = 64 - 3
178183
179184 @staticmethod
180185 def Process (ctx , * args , ** kwds ):
@@ -201,8 +206,12 @@ def __init__(self, processes=None, initializer=None, initargs=(),
201206
202207 if processes is None :
203208 processes = os .cpu_count () or 1
209+ if sys .platform == 'win32' :
210+ processes = min (processes , self ._MAX_WINDOWS_WORKERS )
204211 if processes < 1 :
205212 raise ValueError ("Number of processes must be at least 1" )
213+ if sys .platform == 'win32' and processes > self ._MAX_WINDOWS_WORKERS :
214+ raise ValueError (f"max_workers must be <= { self ._MAX_WINDOWS_WORKERS } " )
206215 if maxtasksperchild is not None :
207216 if not isinstance (maxtasksperchild , int ) or maxtasksperchild <= 0 :
208217 raise ValueError ("maxtasksperchild must be a positive int or None" )
@@ -920,6 +929,7 @@ def _set(self, i, obj):
920929
921930class ThreadPool (Pool ):
922931 _wrap_exception = False
932+ _MAX_WINDOWS_WORKERS = float ("inf" )
923933
924934 @staticmethod
925935 def Process (ctx , * args , ** kwds ):
0 commit comments