Re: asyncio - how to stop loop?

2014-06-12 Thread Frank Millman

Ian Kelly ian.g.ke...@gmail.com wrote in message 
news:CALwzidnv07Wba9WJ=nuc0_v4mvudyaxwh6bgjvw0o1hf3oo...@mail.gmail.com...
 On Wed, Jun 11, 2014 at 1:19 AM, Frank Millman fr...@chagford.com wrote:
 First attempt - same as before

 loop = asyncio.get_event_loop()
 threading.Thread(target=loop.run_forever).start()
 input('Press enter to stop')
 loop.stop()
 loop.close()

 Each event loop is hosted by a specific thread.  In this case you're
 getting the event loop of the main thread and then trying to run it in
 a separate thread, which is not a good idea.  You can run an event
 loop in a separate thread, but you should install a separate event
 loop for that thread if you do (and then when you interact with the
 loop, do so in a thread-safe manner -- see below).

 Second attempt - move the keyboard input to a separate thread

 def stop_loop():
 input('Press enter to stop')
 loop.stop()
 loop.close()

 loop = asyncio.get_event_loop()
 threading.Thread(target=stop_loop).start()
 loop.run_forever()

 One issue here is that (like most event loop implementations) event
 loops are not thread-safe.  To make a call to the event loop across
 threads, you should be using the call_soon_threadsafe method, e.g.
 loop.call_soon_threadsafe(loop.stop).  You'll also want to make sure
 that the event loop has actually stopped before you call loop.close --
 see below.

 Third attempt - get the loop to close itself (cannot use in practice, but
 see what happens)

 def stop_loop():
 loop.stop()
 loop.close()

 loop = asyncio.get_event_loop()
 loop.call_later(2, stop_loop)
 loop.run_forever()

 I think what's happening here is that per the docs loop.close should
 not be called while the loop is running.  You've called loop.stop but
 you're still inside a callback, which is a bit of a gray area.  You
 probably don't need to call loop.close at all, but if you want to do
 so I suggest putting it after the run_forever call, so you can be
 certain the loop has stopped when it's called.

 Putting all that together, you should have something like this:

def stop_loop():
input('Press enter to stop')
loop.call_soon_threadsafe(loop.stop)

loop = asyncio.get_event_loop()
threading.Thread(target=stop_loop).start()
loop.run_forever()
loop.close()  # optional

Thanks very much for the very clear explanation.

Your solution works perfectly.

Much appreciated.

Frank



-- 
https://mail.python.org/mailman/listinfo/python-list


asyncio - how to stop loop?

2014-06-11 Thread Frank Millman
Hi all

I have a 'start.py' script that kicks off my program by starting a number of 
services.

For now, I stop it by allowing the user to press enter, after which I 
close down the services and stop the program. (For production I imagine it 
would be better to run it in the background and send it some kind of signal 
to terminate, but for testing this suffices.)

As one of the services is a 'listening' loop, which would normally prevent 
access to the keyboard, I start it in a separate thread. For example, when I 
was using cherrypy as the server, I had -

server = cherrypy.wsgiserver.CherryPyWSGIServer((host, port), 
dispatcher)
threading.Thread(target=server.start).start()
input('Press enter to stop')
server.stop()

Now I am playing with asyncio, but I cannot get it to behave the same.

Here are my attempts. I use python 3.4.1, and I tested on Windows and 
Linux - the results are different on each platform.

First attempt - same as before

loop = asyncio.get_event_loop()
threading.Thread(target=loop.run_forever).start()
input('Press enter to stop')
loop.stop()
loop.close()

Windows traceback -

Exception in thread Thread-1:
Traceback (most recent call last):
  File C:\Python34\lib\threading.py, line 920, in _bootstrap_inner
self.run()
  File C:\Python34\lib\threading.py, line 868, in run
self._target(*self._args, **self._kwargs)
  File C:\Python34\lib\asyncio\base_events.py, line 184, in run_forever
self._run_once()
  File C:\Python34\lib\asyncio\base_events.py, line 795, in _run_once
event_list = self._selector.select(timeout)
AttributeError: 'NoneType' object has no attribute 'select'

With Linux, it does not terminate. If I press Ctrl_C, I get this traceback 
(hope there are no typos) -

Traceback (most recent call last):
  File /usr/local/lib/python3.4/threading.py, line 1294, in _shutdown
t.join()
  File /usr/local/lib/python3.4/threading.py, line 1060, in join
self._wait_for_tstate_lock()
  File /usr/local/lib/python3.4/threading.py, line 1076, in 
_wait_for_tstate_lock
elif lock.acquire(block, timeout):
KeyboardInterrupt


Second attempt - move the keyboard input to a separate thread

def stop_loop():
input('Press enter to stop')
loop.stop()
loop.close()

loop = asyncio.get_event_loop()
threading.Thread(target=stop_loop).start()
loop.run_forever()

With Windows, it works - the program closes cleanly.

With Linux, it does not terminate. If I press Ctrl_C, I get this traceback 
(hope there are no typos) -

Traceback (most recent call last):
  File test_async.py, line 20, in module
loop.run_forever()
  File /usr/local/lib/python3.4/asyncio.base_events.py, line 184, in 
run_forever
self._run_once()
  File /usr/local/lib/python3.4/asyncio.base_events.py, line 795, in 
_run_once
event_list = self._selector.select(timeout)
  File /usr/local/lib/python3.4/asyncio.selectors.py, line 424, in select
fd_event_list = self._epoll.poll(timeout, max_cv)
KeyboardInterrupt


Third attempt - get the loop to close itself (cannot use in practice, but 
see what happens)

def stop_loop():
loop.stop()
loop.close()

loop = asyncio.get_event_loop()
loop.call_later(2, stop_loop)
loop.run_forever()

Both platforms show the same traceback, after two seconds -

Traceback (most recent call last):
  File C:\Documents and Settings\frank\aib\aib_async\test_async.py, line 
29, in module
loop.run_forever()
  File C:\Python34\lib\asyncio\base_events.py, line 184, in run_forever
self._run_once()
  File C:\Python34\lib\asyncio\base_events.py, line 795, in _run_once
event_list = self._selector.select(timeout)
AttributeError: 'NoneType' object has no attribute 'select'

Can anyone suggest a way to get the loop to stop cleanly?

Thanks

Frank Millman



-- 
https://mail.python.org/mailman/listinfo/python-list


Re: asyncio - how to stop loop?

2014-06-11 Thread Ian Kelly
On Wed, Jun 11, 2014 at 1:19 AM, Frank Millman fr...@chagford.com wrote:
 First attempt - same as before

 loop = asyncio.get_event_loop()
 threading.Thread(target=loop.run_forever).start()
 input('Press enter to stop')
 loop.stop()
 loop.close()

Each event loop is hosted by a specific thread.  In this case you're
getting the event loop of the main thread and then trying to run it in
a separate thread, which is not a good idea.  You can run an event
loop in a separate thread, but you should install a separate event
loop for that thread if you do (and then when you interact with the
loop, do so in a thread-safe manner -- see below).

 Second attempt - move the keyboard input to a separate thread

 def stop_loop():
 input('Press enter to stop')
 loop.stop()
 loop.close()

 loop = asyncio.get_event_loop()
 threading.Thread(target=stop_loop).start()
 loop.run_forever()

One issue here is that (like most event loop implementations) event
loops are not thread-safe.  To make a call to the event loop across
threads, you should be using the call_soon_threadsafe method, e.g.
loop.call_soon_threadsafe(loop.stop).  You'll also want to make sure
that the event loop has actually stopped before you call loop.close --
see below.

 Third attempt - get the loop to close itself (cannot use in practice, but
 see what happens)

 def stop_loop():
 loop.stop()
 loop.close()

 loop = asyncio.get_event_loop()
 loop.call_later(2, stop_loop)
 loop.run_forever()

I think what's happening here is that per the docs loop.close should
not be called while the loop is running.  You've called loop.stop but
you're still inside a callback, which is a bit of a gray area.  You
probably don't need to call loop.close at all, but if you want to do
so I suggest putting it after the run_forever call, so you can be
certain the loop has stopped when it's called.

Putting all that together, you should have something like this:

def stop_loop():
input('Press enter to stop')
loop.call_soon_threadsafe(loop.stop)

loop = asyncio.get_event_loop()
threading.Thread(target=stop_loop).start()
loop.run_forever()
loop.close()  # optional
-- 
https://mail.python.org/mailman/listinfo/python-list