Skip to content

Commit bd4b1a1

Browse files
authored
Merge pull request #3921 from youknowone/update-threading
Update thread/threading/concurrent from CPython 3.10.5
2 parents 3062a75 + 413a668 commit bd4b1a1

File tree

8 files changed

+1093
-467
lines changed

8 files changed

+1093
-467
lines changed

Lib/concurrent/futures/_base.py

+36-38
Original file line numberDiff line numberDiff line change
@@ -284,13 +284,14 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
284284
A named 2-tuple of sets. The first set, named 'done', contains the
285285
futures that completed (is finished or cancelled) before the wait
286286
completed. The second set, named 'not_done', contains uncompleted
287-
futures.
287+
futures. Duplicate futures given to *fs* are removed and will be
288+
returned only once.
288289
"""
290+
fs = set(fs)
289291
with _AcquireFutures(fs):
290-
done = set(f for f in fs
291-
if f._state in [CANCELLED_AND_NOTIFIED, FINISHED])
292-
not_done = set(fs) - done
293-
292+
done = {f for f in fs
293+
if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]}
294+
not_done = fs - done
294295
if (return_when == FIRST_COMPLETED) and done:
295296
return DoneAndNotDoneFutures(done, not_done)
296297
elif (return_when == FIRST_EXCEPTION) and done:
@@ -309,7 +310,7 @@ def wait(fs, timeout=None, return_when=ALL_COMPLETED):
309310
f._waiters.remove(waiter)
310311

311312
done.update(waiter.finished_futures)
312-
return DoneAndNotDoneFutures(done, set(fs) - done)
313+
return DoneAndNotDoneFutures(done, fs - done)
313314

314315
class Future(object):
315316
"""Represents the result of an asynchronous computation."""
@@ -380,13 +381,17 @@ def running(self):
380381
return self._state == RUNNING
381382

382383
def done(self):
383-
"""Return True of the future was cancelled or finished executing."""
384+
"""Return True if the future was cancelled or finished executing."""
384385
with self._condition:
385386
return self._state in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED]
386387

387388
def __get_result(self):
388389
if self._exception:
389-
raise self._exception
390+
try:
391+
raise self._exception
392+
finally:
393+
# Break a reference cycle with the exception in self._exception
394+
self = None
390395
else:
391396
return self._result
392397

@@ -426,20 +431,24 @@ def result(self, timeout=None):
426431
timeout.
427432
Exception: If the call raised then that exception will be raised.
428433
"""
429-
with self._condition:
430-
if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
431-
raise CancelledError()
432-
elif self._state == FINISHED:
433-
return self.__get_result()
434-
435-
self._condition.wait(timeout)
436-
437-
if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
438-
raise CancelledError()
439-
elif self._state == FINISHED:
440-
return self.__get_result()
441-
else:
442-
raise TimeoutError()
434+
try:
435+
with self._condition:
436+
if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
437+
raise CancelledError()
438+
elif self._state == FINISHED:
439+
return self.__get_result()
440+
441+
self._condition.wait(timeout)
442+
443+
if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]:
444+
raise CancelledError()
445+
elif self._state == FINISHED:
446+
return self.__get_result()
447+
else:
448+
raise TimeoutError()
449+
finally:
450+
# Break a reference cycle with the exception in self._exception
451+
self = None
443452

444453
def exception(self, timeout=None):
445454
"""Return the exception raised by the call that the future represents.
@@ -550,7 +559,7 @@ def set_exception(self, exception):
550559
class Executor(object):
551560
"""This is an abstract base class for concrete asynchronous executors."""
552561

553-
def submit(*args, **kwargs):
562+
def submit(self, fn, /, *args, **kwargs):
554563
"""Submits a callable to be executed with the given arguments.
555564
556565
Schedules the callable to be executed as fn(*args, **kwargs) and returns
@@ -559,21 +568,7 @@ def submit(*args, **kwargs):
559568
Returns:
560569
A Future representing the given call.
561570
"""
562-
if len(args) >= 2:
563-
pass
564-
elif not args:
565-
raise TypeError("descriptor 'submit' of 'Executor' object "
566-
"needs an argument")
567-
elif 'fn' in kwargs:
568-
import warnings
569-
warnings.warn("Passing 'fn' as keyword argument is deprecated",
570-
DeprecationWarning, stacklevel=2)
571-
else:
572-
raise TypeError('submit expected at least 1 positional argument, '
573-
'got %d' % (len(args)-1))
574-
575571
raise NotImplementedError()
576-
submit.__text_signature__ = '($self, fn, /, *args, **kwargs)'
577572

578573
def map(self, fn, *iterables, timeout=None, chunksize=1):
579574
"""Returns an iterator equivalent to map(fn, iter).
@@ -619,7 +614,7 @@ def result_iterator():
619614
future.cancel()
620615
return result_iterator()
621616

622-
def shutdown(self, wait=True):
617+
def shutdown(self, wait=True, *, cancel_futures=False):
623618
"""Clean-up the resources associated with the Executor.
624619
625620
It is safe to call this method several times. Otherwise, no other
@@ -629,6 +624,9 @@ def shutdown(self, wait=True):
629624
wait: If True then shutdown will not return until all running
630625
futures have finished executing and the resources used by the
631626
executor have been reclaimed.
627+
cancel_futures: If True then shutdown will cancel all pending
628+
futures. Futures that are completed or running will not be
629+
cancelled.
632630
"""
633631
pass
634632

0 commit comments

Comments
 (0)