Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
41f69f4c
Commit
41f69f4c
authored
Nov 19, 2015
by
Guido van Rossum
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #25593: Change semantics of EventLoop.stop().
parent
01a65af4
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
87 additions
and
28 deletions
+87
-28
Doc/library/asyncio-eventloop.rst
Doc/library/asyncio-eventloop.rst
+16
-6
Doc/library/asyncio-protocol.rst
Doc/library/asyncio-protocol.rst
+1
-1
Lib/asyncio/base_events.py
Lib/asyncio/base_events.py
+9
-16
Lib/asyncio/test_utils.py
Lib/asyncio/test_utils.py
+6
-5
Lib/test/test_asyncio/test_base_events.py
Lib/test/test_asyncio/test_base_events.py
+53
-0
Misc/NEWS
Misc/NEWS
+2
-0
No files found.
Doc/library/asyncio-eventloop.rst
View file @
41f69f4c
...
...
@@ -29,7 +29,16 @@ Run an event loop
.. method:: BaseEventLoop.run_forever()
Run until :meth:`stop` is called.
Run until :meth:`stop` is called. If :meth:`stop` is called before
:meth:`run_forever()` is called, this polls the I/O selector once
with a timeout of zero, runs all callbacks scheduled in response to
I/O events (and those that were already scheduled), and then exits.
If :meth:`stop` is called while :meth:`run_forever` is running,
this will run the current batch of callbacks and then exit. Note
that callbacks scheduled by callbacks will not run in that case;
they will run the next time :meth:`run_forever` is called.
.. versionchanged:: 3.4.4
.. method:: BaseEventLoop.run_until_complete(future)
...
...
@@ -48,10 +57,10 @@ Run an event loop
Stop running the event loop.
Every callback scheduled before :meth:`stop` is called will run.
Callbacks scheduled after :meth:`stop` is called will not run
.
However, those callbacks will run if :meth:`run_forever` is called
again later.
This causes :meth:`run_forever` to exit at the next suitable
opportunity (see there for more details)
.
.. versionchanged:: 3.4.4
.. method:: BaseEventLoop.is_closed()
...
...
@@ -61,7 +70,8 @@ Run an event loop
.. method:: BaseEventLoop.close()
Close the event loop. The loop must not be running.
Close the event loop. The loop must not be running. Pending
callbacks will be lost.
This clears the queues and shuts down the executor, but does not wait for
the executor to finish.
...
...
Doc/library/asyncio-protocol.rst
View file @
41f69f4c
...
...
@@ -494,7 +494,7 @@ data and wait until the connection is closed::
def connection_lost(self, exc):
print('The server closed the connection')
print('Stop the event lop')
print('Stop the event lo
o
p')
self.loop.stop()
loop = asyncio.get_event_loop()
...
...
Lib/asyncio/base_events.py
View file @
41f69f4c
...
...
@@ -70,10 +70,6 @@ def _format_pipe(fd):
return
repr
(
fd
)
class
_StopError
(
BaseException
):
"""Raised to stop the event loop."""
def
_check_resolved_address
(
sock
,
address
):
# Ensure that the address is already resolved to avoid the trap of hanging
# the entire event loop when the address requires doing a DNS lookup.
...
...
@@ -118,9 +114,6 @@ def _check_resolved_address(sock, address):
"got host %r: %s"
%
(
host
,
err
))
def
_raise_stop_error
(
*
args
):
raise
_StopError
def
_run_until_complete_cb
(
fut
):
exc
=
fut
.
_exception
...
...
@@ -129,7 +122,7 @@ def _run_until_complete_cb(fut):
# Issue #22429: run_forever() already finished, no need to
# stop it.
return
_raise_stop_error
()
fut
.
_loop
.
stop
()
class
Server
(
events
.
AbstractServer
):
...
...
@@ -184,6 +177,7 @@ class BaseEventLoop(events.AbstractEventLoop):
def
__init__
(
self
):
self
.
_timer_cancelled_count
=
0
self
.
_closed
=
False
self
.
_stopping
=
False
self
.
_ready
=
collections
.
deque
()
self
.
_scheduled
=
[]
self
.
_default_executor
=
None
...
...
@@ -298,11 +292,11 @@ class BaseEventLoop(events.AbstractEventLoop):
self
.
_thread_id
=
threading
.
get_ident
()
try
:
while
True
:
try
:
self
.
_run_once
()
except
_StopError
:
self
.
_run_once
()
if
self
.
_stopping
:
break
finally
:
self
.
_stopping
=
False
self
.
_thread_id
=
None
self
.
_set_coroutine_wrapper
(
False
)
...
...
@@ -345,11 +339,10 @@ class BaseEventLoop(events.AbstractEventLoop):
def
stop
(
self
):
"""Stop running the event loop.
Every callback scheduled before stop() is called will run. Callbacks
scheduled after stop() is called will not run. However, those callbacks
will run if run_forever is called again later.
Every callback already scheduled will still run. This simply informs
run_forever to stop looping after a complete iteration.
"""
self
.
call_soon
(
_raise_stop_error
)
self
.
_stopping
=
True
def
close
(
self
):
"""Close the event loop.
...
...
@@ -1194,7 +1187,7 @@ class BaseEventLoop(events.AbstractEventLoop):
handle
.
_scheduled
=
False
timeout
=
None
if
self
.
_ready
:
if
self
.
_ready
or
self
.
_stopping
:
timeout
=
0
elif
self
.
_scheduled
:
# Compute the desired timeout.
...
...
Lib/asyncio/test_utils.py
View file @
41f69f4c
...
...
@@ -71,12 +71,13 @@ def run_until(loop, pred, timeout=30):
def
run_once
(
loop
):
"""loop.stop() schedules _raise_stop_error()
and run_forever() runs until _raise_stop_error() callback.
this wont work if test waits for some IO events, because
_raise_stop_error() runs before any of io events callbacks.
"""Legacy API to run once through the event loop.
This is the recommended pattern for test code. It will poll the
selector once and run all callbacks scheduled in response to I/O
events.
"""
loop
.
stop
(
)
loop
.
call_soon
(
loop
.
stop
)
loop
.
run_forever
()
...
...
Lib/test/test_asyncio/test_base_events.py
View file @
41f69f4c
...
...
@@ -757,6 +757,59 @@ class BaseEventLoopTests(test_utils.TestCase):
pass
self
.
assertTrue
(
func
.
called
)
def
test_single_selecter_event_callback_after_stopping
(
self
):
# Python issue #25593: A stopped event loop may cause event callbacks
# to run more than once.
event_sentinel
=
object
()
callcount
=
0
doer
=
None
def
proc_events
(
event_list
):
nonlocal
doer
if
event_sentinel
in
event_list
:
doer
=
self
.
loop
.
call_soon
(
do_event
)
def
do_event
():
nonlocal
callcount
callcount
+=
1
self
.
loop
.
call_soon
(
clear_selector
)
def
clear_selector
():
doer
.
cancel
()
self
.
loop
.
_selector
.
select
.
return_value
=
()
self
.
loop
.
_process_events
=
proc_events
self
.
loop
.
_selector
.
select
.
return_value
=
(
event_sentinel
,)
for
i
in
range
(
1
,
3
):
with
self
.
subTest
(
'Loop %d/2'
%
i
):
self
.
loop
.
call_soon
(
self
.
loop
.
stop
)
self
.
loop
.
run_forever
()
self
.
assertEqual
(
callcount
,
1
)
def
test_run_once
(
self
):
# Simple test for test_utils.run_once(). It may seem strange
# to have a test for this (the function isn't even used!) but
# it's a de-factor standard API for library tests. This tests
# the idiom: loop.call_soon(loop.stop); loop.run_forever().
count
=
0
def
callback
():
nonlocal
count
count
+=
1
self
.
loop
.
_process_events
=
mock
.
Mock
()
self
.
loop
.
call_soon
(
callback
)
test_utils
.
run_once
(
self
.
loop
)
self
.
assertEqual
(
count
,
1
)
def
test_run_forever_pre_stopped
(
self
):
# Test that the old idiom for pre-stopping the loop works.
self
.
loop
.
_process_events
=
mock
.
Mock
()
self
.
loop
.
stop
()
self
.
loop
.
run_forever
()
self
.
loop
.
_selector
.
select
.
assert_called_once_with
(
0
)
class
MyProto
(
asyncio
.
Protocol
):
done
=
None
...
...
Misc/NEWS
View file @
41f69f4c
...
...
@@ -106,6 +106,8 @@ Core and Builtins
Library
-------
- Issue #25593: Change semantics of EventLoop.stop() in asyncio.
- Issue #6973: When we know a subprocess.Popen process has died, do
not allow the send_signal(), terminate(), or kill() methods to do
anything as they could potentially signal a different process.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment