johhny B
johhny B

Reputation: 1452

Tornado Execution Order Spawn callback

If I have something like the following:

 @tornado.gen.coroutine
 def first(x):
    # 
    # do stuff


    for i in I:
       tornado.ioloop.IOLoop.current().spawn_callback(func,i)

    tornado.ioloop.IOLoop.current().spawn_callback(func2,z)

 yield first(xxx)

Can I be guaranteed that all the spawned functions in the for loop will run before the last spawning of callback to func2()?

Upvotes: 1

Views: 2950

Answers (1)

A. Jesse Jiryu Davis
A. Jesse Jiryu Davis

Reputation: 24007

No, in fact you're guaranteed that all the functions are spawned before any of them starts running, because first does not yield between spawning func and spawning func2. You can verify this yourself by testing your code:

from tornado import gen, ioloop

@gen.coroutine
def func():
    print('func started')
    yield gen.moment
    print('func done')


@gen.coroutine
def func2():
    print('func2 started')
    yield gen.moment
    print('func2 done')


@gen.coroutine
def first():
    for i in range(2):
        ioloop.IOLoop.current().spawn_callback(func)

    ioloop.IOLoop.current().spawn_callback(func2)
    yield gen.sleep(1)

ioloop.IOLoop.current().run_sync(first)

It prints:

func started
func started
func2 started
func done
func done
func2 done

See, func2 begins before the coroutines running func complete.

To accomplish what you want:

@gen.coroutine
def first():
    yield [func() for i in range(2)]
    ioloop.IOLoop.current().spawn_callback(func2)

This prints:

func started
func started
func done
func done
func2 started
func2 done

If you want first to wait for func2 to finish before it exits, then:

@gen.coroutine
def first():
    yield [func() for i in range(2)]
    yield func2()

For more info on calling coroutines from coroutines, see my Refactoring Tornado Coroutines.

Upvotes: 8

Related Questions