Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 491a912

Browse files
committed
Issue #28600: Optimize loop.call_soon().
Run expensive type checks only in debug mode. In addition, stop supporting passing handles to loop.run_in_executor.
1 parent 9e80eeb commit 491a912

5 files changed

Lines changed: 29 additions & 57 deletions

File tree

Lib/asyncio/base_events.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -528,12 +528,10 @@ def call_at(self, when, callback, *args):
528528
529529
Absolute time corresponds to the event loop's time() method.
530530
"""
531-
if (coroutines.iscoroutine(callback)
532-
or coroutines.iscoroutinefunction(callback)):
533-
raise TypeError("coroutines cannot be used with call_at()")
534531
self._check_closed()
535532
if self._debug:
536533
self._check_thread()
534+
self._check_callback(callback, 'call_at')
537535
timer = events.TimerHandle(when, callback, args, self)
538536
if timer._source_traceback:
539537
del timer._source_traceback[-1]
@@ -551,18 +549,27 @@ def call_soon(self, callback, *args):
551549
Any positional arguments after the callback will be passed to
552550
the callback when it is called.
553551
"""
552+
self._check_closed()
554553
if self._debug:
555554
self._check_thread()
555+
self._check_callback(callback, 'call_soon')
556556
handle = self._call_soon(callback, args)
557557
if handle._source_traceback:
558558
del handle._source_traceback[-1]
559559
return handle
560560

561+
def _check_callback(self, callback, method):
562+
if (coroutines.iscoroutine(callback) or
563+
coroutines.iscoroutinefunction(callback)):
564+
raise TypeError(
565+
"coroutines cannot be used with {}()".format(method))
566+
if not callable(callback):
567+
raise TypeError(
568+
'a callable object was expected by {}(), got {!r}'.format(
569+
method, callback))
570+
571+
561572
def _call_soon(self, callback, args):
562-
if (coroutines.iscoroutine(callback)
563-
or coroutines.iscoroutinefunction(callback)):
564-
raise TypeError("coroutines cannot be used with call_soon()")
565-
self._check_closed()
566573
handle = events.Handle(callback, args, self)
567574
if handle._source_traceback:
568575
del handle._source_traceback[-1]
@@ -588,28 +595,19 @@ def _check_thread(self):
588595

589596
def call_soon_threadsafe(self, callback, *args):
590597
"""Like call_soon(), but thread-safe."""
598+
self._check_closed()
599+
if self._debug:
600+
self._check_callback(callback, 'call_soon_threadsafe')
591601
handle = self._call_soon(callback, args)
592602
if handle._source_traceback:
593603
del handle._source_traceback[-1]
594604
self._write_to_self()
595605
return handle
596606

597607
def run_in_executor(self, executor, func, *args):
598-
if (coroutines.iscoroutine(func)
599-
or coroutines.iscoroutinefunction(func)):
600-
raise TypeError("coroutines cannot be used with run_in_executor()")
601608
self._check_closed()
602-
if isinstance(func, events.Handle):
603-
assert not args
604-
assert not isinstance(func, events.TimerHandle)
605-
warnings.warn(
606-
"Passing Handle to loop.run_in_executor() is deprecated",
607-
DeprecationWarning)
608-
if func._cancelled:
609-
f = self.create_future()
610-
f.set_result(None)
611-
return f
612-
func, args = func._callback, func._args
609+
if self._debug:
610+
self._check_callback(func, 'run_in_executor')
613611
if executor is None:
614612
executor = self._default_executor
615613
if executor is None:

Lib/asyncio/events.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ class Handle:
8282
'_source_traceback', '_repr', '__weakref__')
8383

8484
def __init__(self, callback, args, loop):
85-
assert not isinstance(callback, Handle), 'A Handle is not a callback'
8685
self._loop = loop
8786
self._callback = callback
8887
self._args = args

Lib/test/test_asyncio/test_base_events.py

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ def cb():
235235
self.assertIsInstance(h, asyncio.Handle)
236236
self.assertIn(h, self.loop._ready)
237237

238+
def test_call_soon_non_callable(self):
239+
self.loop.set_debug(True)
240+
with self.assertRaisesRegex(TypeError, 'a callable object'):
241+
self.loop.call_soon(1)
242+
238243
def test_call_later(self):
239244
def cb():
240245
pass
@@ -341,47 +346,21 @@ def test_thread(loop, debug, create_loop=False):
341346
# check disabled if debug mode is disabled
342347
test_thread(self.loop, False, create_loop=True)
343348

344-
def test_run_once_in_executor_handle(self):
345-
def cb():
346-
pass
347-
348-
self.assertRaises(
349-
AssertionError, self.loop.run_in_executor,
350-
None, asyncio.Handle(cb, (), self.loop), ('',))
351-
self.assertRaises(
352-
AssertionError, self.loop.run_in_executor,
353-
None, asyncio.TimerHandle(10, cb, (), self.loop))
354-
355-
def test_run_once_in_executor_cancelled(self):
356-
def cb():
357-
pass
358-
h = asyncio.Handle(cb, (), self.loop)
359-
h.cancel()
360-
361-
with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"):
362-
f = self.loop.run_in_executor(None, h)
363-
self.assertIsInstance(f, asyncio.Future)
364-
self.assertTrue(f.done())
365-
self.assertIsNone(f.result())
366-
367349
def test_run_once_in_executor_plain(self):
368350
def cb():
369351
pass
370-
h = asyncio.Handle(cb, (), self.loop)
371352
f = asyncio.Future(loop=self.loop)
372353
executor = mock.Mock()
373354
executor.submit.return_value = f
374355

375356
self.loop.set_default_executor(executor)
376357

377-
with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"):
378-
res = self.loop.run_in_executor(None, h)
358+
res = self.loop.run_in_executor(None, cb)
379359
self.assertIs(f, res)
380360

381361
executor = mock.Mock()
382362
executor.submit.return_value = f
383-
with self.assertWarnsRegex(DeprecationWarning, "Passing Handle"):
384-
res = self.loop.run_in_executor(executor, h)
363+
res = self.loop.run_in_executor(executor, cb)
385364
self.assertIs(f, res)
386365
self.assertTrue(executor.submit.called)
387366

@@ -1666,6 +1645,7 @@ def test_call_coroutine(self):
16661645
def simple_coroutine():
16671646
pass
16681647

1648+
self.loop.set_debug(True)
16691649
coro_func = simple_coroutine
16701650
coro_obj = coro_func()
16711651
self.addCleanup(coro_obj.close)

Lib/test/test_asyncio/test_events.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,13 +2249,6 @@ def callback(*args):
22492249
h.cancel()
22502250
self.assertTrue(h._cancelled)
22512251

2252-
def test_handle_from_handle(self):
2253-
def callback(*args):
2254-
return args
2255-
h1 = asyncio.Handle(callback, (), loop=self.loop)
2256-
self.assertRaises(
2257-
AssertionError, asyncio.Handle, h1, (), self.loop)
2258-
22592252
def test_callback_with_exception(self):
22602253
def callback():
22612254
raise ValueError()

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ Library
441441
threadpool executor.
442442
Initial patch by Hans Lawrenz.
443443

444+
- Issue #28600: Optimize loop.call_soon().
445+
444446
IDLE
445447
----
446448

0 commit comments

Comments
 (0)