@@ -77,6 +77,10 @@ class Semaphore(AbstractLinkable): # pylint:disable=undefined-variable
7777 .. versionchanged:: 20.12.0
7878 Improved support for multi-threaded usage. When multi-threaded usage is detected,
7979 instances will no longer create the thread's hub if it's not present.
80+
81+ .. versionchanged:: NEXT
82+ Uses Python 3 native lock timeouts for cross-thread operations instead
83+ of spinning.
8084 """
8185
8286 __slots__ = (
@@ -449,22 +453,16 @@ def __acquire_without_hubs(self, timeout):
449453 return False
450454
451455 def __spin_on_native_lock (self , thread_lock , timeout ):
452- expiration = 0
453- if timeout :
454- expiration = monotonic () + timeout
455-
456456 self ._drop_lock_for_switch_out ()
457457 try :
458- # TODO: When timeout is given and the lock supports that
459- # (Python 3), pass that.
460- # Python 2 has terrible behaviour where lock acquires can't
461- # be interrupted, so we use a spin loop
462- while not thread_lock .acquire (0 ):
463- if expiration and monotonic () >= expiration :
464- return False
465-
466- _native_sleep (0.001 )
467- return True
458+ # Unlike Python 2, Python 3 thread locks
459+ # can be interrupted when blocking, with or
460+ # without a timeout. Python 2 didn't even
461+ # support a timeout for non -blocking.
462+ if timeout :
463+ return thread_lock .acquire (True , timeout )
464+
465+ return thread_lock .acquire ()
468466 finally :
469467 self ._acquire_lock_for_switch_in ()
470468
0 commit comments