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()?
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.