5

I'm writing a coroutine to execute shell command in python base on a tutorial. Here are basic:

import asyncio

async def async_procedure():
    process = await asyncio.create_subprocess_exec('ping', '-c', '2', 'google.com')
    await process.wait()
    print('async procedure done.')

loop = asyncio.get_event_loop()
loop.run_until_complete(async_procedure())
loop.close()

This code above work perfectly. It gives a result like that:

PING google.com (...) 56(84) bytes of data.
64 bytes from ...: icmp_seq=1 ttl=46 time=34.8 ms
64 bytes from ...: icmp_seq=2 ttl=46 time=34.5 ms

--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 33.771/34.437/34.881/0.407 ms
Process done!

When I try remove process.wait():

async def async_procedure():
    await asyncio.create_subprocess_exec('ping', '-c', '2', 'google.com')
    print('async procedure done.')

The script doesn't work as expected:

Process done! # This line should be lastest line
PING google.com (...) 56(84) bytes of data.
64 bytes from ...: icmp_seq=1 ttl=46 time=21.1 ms
64 bytes from ...: icmp_seq=2 ttl=46 time=21.8 ms

--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 21.135/21.469/21.803/0.334 ms

But there is no problem in a very similar example:

async def async_procedure():
    await asyncio.sleep(2)
    print('async procedure done')
  • So why await doesn't wait asyncio.create_subprocess_exec() ?

The docs (https://docs.python.org/3/library/asyncio-task.html#coroutine) says:

result = await future or result = yield from future – suspends the coroutine until the future is done, then returns the future’s result, or raises an exception, which will be propagated. (If the future is cancelled, it will raise a CancelledError exception.) Note that tasks are futures, and everything said about futures also applies to tasks.

result = await coroutine or result = yield from coroutine – wait for another coroutine to produce a result (or raise an exception, which will be propagated). The coroutine expression must be a call to another coroutine.

return expression – produce a result to the coroutine that is waiting for this one using await or yield from.

raise exception – raise an exception in the coroutine that is waiting for this one using await or yield from.

  • What is actually process's flow when coroutine suspending and waiting ?

Here are source code of asyncio.create_subprocess_exec() and asyncio.sleep() are coroutine. Both of them are coroutines:

@coroutine
def create_subprocess_exec(program, *args, stdin=None, stdout=None,
                           stderr=None, loop=None,
                           limit=streams._DEFAULT_LIMIT, **kwds):
    if loop is None:
        loop = events.get_event_loop()
    protocol_factory = lambda: SubprocessStreamProtocol(limit=limit,
                                                        loop=loop)
    transport, protocol = yield from loop.subprocess_exec(
                                            protocol_factory,
                                            program, *args,
                                            stdin=stdin, stdout=stdout,
                                            stderr=stderr, **kwds)
    return Process(transport, protocol, loop)


@coroutine
def sleep(delay, result=None, *, loop=None):
    """Coroutine that completes after a given time (in seconds)."""
    if delay == 0:
        yield
        return result

    if loop is None:
        loop = events.get_event_loop()
    future = loop.create_future()
    h = future._loop.call_later(delay,
                                futures._set_result_unless_cancelled,
                                future, result)
    try:
        return (yield from future)
    finally:
        h.cancel()

1 Answer 1

13

You waited for the process to start. You did not wait for it to finish. await process.wait() waits for it to finish.

Sign up to request clarification or add additional context in comments.

1 Comment

I can't believe this problem is so simple. Thank you @user2357112!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.