Simone Bronzini
Simone Bronzini

Reputation: 1077

Python asyncio simple example

I am experimenting a bit with python's asyncio Protocols. I found this example from the official docs and wanted to slightly modify it and reproduce its beahviour. So I wrote the following two scripts:

# file: get_rand.py
from random import choice
from time import sleep

def main():
    print(choice('abcdefghijklmnopqrstuvwxyz'))
    sleep(2)

if __name__ == '__main__':
    main()

and:

# file: async_test.py
import asyncio

class Protocol(asyncio.SubprocessProtocol):

    def __init__(self, exit_future):
        self.exit_future = exit_future
        self.output = bytearray()
        print('Protocol initialised')

    def pipe_data_received(self, fd, data):
        print('Data received')
        self.output.extend(data)

    #def pipe_connection_lost(self, fd, exc):
    #    print('Pipe connection lost for the following reason:')
    #    print(exc)

    def subprocess_exited(self):
        print('Subprocess exited')
        self.exit_future.set_result(True)


@asyncio.coroutine
def get_rand(loop):
    exit_future = asyncio.Future(loop=loop)
    print('Process created')
    created = loop.subprocess_exec(lambda: Protocol(exit_future),
                                   'python3.5', 'get_rand.py',
                                   stdin=None, stderr=None)
    print('Getting pipes...')
    transport, protocol = yield from created
    print('Waiting for child to exit...')
    yield from exit_future
    transport.close()
    print('Gathering data...')
    data = bytes(protocol.output)
    print('Returning data...')
    return data.decode('ascii').rstrip()

def main():
    loop = asyncio.get_event_loop()
    print('Event loop started')
    data = loop.run_until_complete(get_rand(loop))
    print('Event loop ended')
    print(data)
    loop.close()

if __name__ == '__main__':
    main()

When I run async_test.py I get the following output:

$ python3.5 async_test.py 
Event loop started
Process created
Getting pipes...
Protocol initialised
Waiting for child to exit...
Data received

And it just hangs.

If I uncomment the pipe_connection_lost method, the output is the following:

$ python3.5 async_test.py 
Event loop started
Process created
Getting pipes...
Protocol initialised
Waiting for child to exit...
Data received
Pipe connection lost for the following reason:
None

And still the process hangs. What I think is happening is that for some reason the child process (get_rand.py) closes the pipe (as seen in the output above) but does not terminate so that the parent can unblock from yield from exit_future. I really don't understand the reason behind this behaviour, considering that my code is mostly copy-pasted from an example in the python docs.

Upvotes: 2

Views: 1100

Answers (1)

Ivo
Ivo

Reputation: 5420

Change def subprocess_exited(self):

to def process_exited(self):

Upvotes: 4

Related Questions