Message from discussion
How to call tornado asynchronous function right?
Date: Wed, 3 Oct 2012 19:41:42 -0700 (PDT)
From: Jimmy <li.jiam...@gmail.com>
To: python-tornado@googlegroups.com
Message-Id: <32d9aa19-57a1-4a98-8f13-476dbd7d6819@googlegroups.com>
In-Reply-To: <CADjgTRwhisFdrGkwJ6HrCGHb9_moJM9=QY4pppDP1vs5y_d5iQ@mail.gmail.com>
References: <296be41f-1894-4250-be3d-1a2238038d79@googlegroups.com>
<8e2a8f0d-aa90-4948-abf5-b9d9d5d5eb0f@p22g2000vby.googlegroups.com>
<8ff4db59-0c5e-48db-a485-53b7390d8596@googlegroups.com>
<CAFkYKJ4-DBO9oqtmOO6TuJ6Oz0b8qN3-1qREB40G=FevEdw=mg@mail.gmail.com>
<CADjgTRwhisFdrGkwJ6HrCGHb9_moJM9=QY4pppDP1vs5y_d5iQ@mail.gmail.com>
Subject: Re: [tornado] Re: How to call tornado asynchronous function right?
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_Part_640_27727705.1349318502077"
------=_Part_640_27727705.1349318502077
Content-Type: multipart/alternative;
boundary="----=_Part_641_15593101.1349318502077"
------=_Part_641_15593101.1349318502077
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit
Thank you Lorenzo. That's really helpful!
On Wednesday, October 3, 2012 7:36:10 PM UTC+8, Lorenzo Bolla wrote:
>
> I figured that it might be useful to collect answers to all these
> questions, that periodically are asked in this mailing list in a blog post.
>
> Here it is:
> http://lbolla.info/blog/2012/10/03/asynchronous-programming-with-tornado/
>
> If you have comments or you want me to add/correct something, just let me
> know.
>
> L.
>
>
>
>
> On Wed, Oct 3, 2012 at 7:04 AM, Ben Darnell <b...@bendarnell.com<javascript:>
> > wrote:
>
>> Your async_callback version doesn't actually work - it never calls
>> callback_sleep. async_callback is meant to be used as a wrapper to
>> deal with exception handling - it was necessary in early versions of
>> Tornado, but not any more. You probably meant io_loop.add_callback
>> instead of async_callback, but if you make that change you'll see that
>> time.sleep blocks in that version as well.
>>
>> @asynchronous is a declaration, not a directive: it describes the
>> fact that get() is asynchronous (i.e. there is more work to be done
>> after it returns), it doesn't make it so. Tornado's core is still a
>> single-threaded event loop, so to achieve concurrency within a single
>> process you need to use or make non-blocking versions of any
>> time-consuming functions you use (e.g. IOLoop.add_timeout instead of
>> time.sleep, or AsyncHTTPClient instead of HTTPClient or urllib), or
>> hand that work off to another thread or process.
>>
>> -Ben
>>
>> On Tue, Oct 2, 2012 at 8:57 PM, Jimmy <li.ji...@gmail.com <javascript:>>
>> wrote:
>> > I don't mean to make it sleep. You can assume the sleep to some heavy
>> load
>> > work, like loop i from 0 to 10000000000. When multiple requests come in
>> > concurrently, I saw the request is executed in sequence, not in parallel
>> > (using yield gen.Task). But the old way of async_callback works.
>> >
>> > How to use gen.Task to create async behavior?
>> >
>> >
>> > On Wednesday, October 3, 2012 5:51:54 AM UTC+8, aliane abdelouahab
>> wrote:
>> >>
>> >> look here, maybe it will help:
>> >>
>> >>
>> http://groups.google.com/group/python-tornado/browse_thread/thread/ae9b7527bf3d8948
>> >>
>> >> On 2 oct, 11:08, Li jiaming <li.jiam...@gmail.com> wrote:
>> >> > I created a simple app with gen.task. But seems doesn't work
>> >> > asynchronously. I try to call /sleep for multiple times, but it
>> handles
>> >> > request in sequence.
>> >> >
>> >> > import tornado.ioloop
>> >> > import tornado.web
>> >> > from tornado.web import asynchronous
>> >> > from tornado import gen
>> >> > import time
>> >> > import tornado.httpserver
>> >> >
>> >> > class MainHandler(tornado.web.RequestHandler):
>> >> > def get(self):
>> >> > print 'receive root request'
>> >> > self.write("Hello, world")
>> >> >
>> >> > class SleepHandler(tornado.web.RequestHandler):
>> >> > @asynchronous
>> >> > @gen.engine
>> >> > def get(self):
>> >> > print 'receive sleep request'
>> >> > yield [ gen.Task(self.sleep, 10),
>> >> > gen.Task(self.sleep, 9)]
>> >> > self.write("Wake up")
>> >> > self.finish()
>> >> >
>> >> > def sleep(self, sec, callback):
>> >> > print 'sleep for %d seconds' % sec
>> >> > time.sleep(sec)
>> >> > print 'finish sleep %d' % sec
>> >> > return callback()
>> >> >
>> >> > application = tornado.web.Application([
>> >> > (r"/", MainHandler),
>> >> > (r"/sleep", SleepHandler),
>> >> > ])
>> >> >
>> >> > if __name__ == "__main__":
>> >> > server = tornado.httpserver.HTTPServer(application)
>> >> > server.listen(8888)
>> >> > tornado.ioloop.IOLoop.instance().start()
>> >> >
>> >> > *Anything wrong in my code?*
>> >> >
>> >> > I also tried async_callback (which is claimed to be obsoleted way of
>> >> > doing
>> >> > async). But it works. It can handle multiple requests in parallel
>> when
>> >> > calling /sleep.
>> >> >
>> >> > class SleepHandler(tornado.web.RequestHandler):
>> >> > @asynchronous
>> >> > def get(self):
>> >> > print 'receive sleep request'
>> >> > self.async_callback(self.callback_sleep, 10)
>> >> >
>> >> > def callback_sleep(self, sec):
>> >> > print 'callback sleep for %d seconds' % sec
>> >> > time.sleep(sec)
>> >> > print 'finish callback sleep for %d seconds' % sec
>> >> > self.write('wake up')
>> >> > self.finish()
>>
>
>
------=_Part_641_15593101.1349318502077
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit
Thank you Lorenzo. That's really helpful!<div><br>On Wednesday, October 3, 2012 7:36:10 PM UTC+8, Lorenzo Bolla wrote:<blockquote class="gmail_quote" style="margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">I figured that it might be useful to collect answers to all these questions, that periodically are asked in this mailing list in a blog post.<div><br></div><div>Here it is:</div><div><a href="http://lbolla.info/blog/2012/10/03/asynchronous-programming-with-tornado/" target="_blank">http://lbolla.info/blog/2012/<wbr>10/03/asynchronous-<wbr>programming-with-tornado/</a></div>
<div><br></div><div>If you have comments or you want me to add/correct something, just let me know.</div><div><br></div><div>L.</div><div><br></div><div><br></div><div><br><br><div class="gmail_quote">On Wed, Oct 3, 2012 at 7:04 AM, Ben Darnell <span dir="ltr"><<a href="javascript:" target="_blank" gdf-obfuscated-mailto="xuL5JSSKTIwJ">b...@bendarnell.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Your async_callback version doesn't actually work - it never calls<br>
callback_sleep. async_callback is meant to be used as a wrapper to<br>
deal with exception handling - it was necessary in early versions of<br>
Tornado, but not any more. You probably meant io_loop.add_callback<br>
instead of async_callback, but if you make that change you'll see that<br>
time.sleep blocks in that version as well.<br>
<br>
@asynchronous is a declaration, not a directive: it describes the<br>
fact that get() is asynchronous (i.e. there is more work to be done<br>
after it returns), it doesn't make it so. Tornado's core is still a<br>
single-threaded event loop, so to achieve concurrency within a single<br>
process you need to use or make non-blocking versions of any<br>
time-consuming functions you use (e.g. IOLoop.add_timeout instead of<br>
time.sleep, or AsyncHTTPClient instead of HTTPClient or urllib), or<br>
hand that work off to another thread or process.<br>
<span><font color="#888888"><br>
-Ben<br>
</font></span><div><div><br>
On Tue, Oct 2, 2012 at 8:57 PM, Jimmy <<a href="javascript:" target="_blank" gdf-obfuscated-mailto="xuL5JSSKTIwJ">li.ji...@gmail.com</a>> wrote:<br>
> I don't mean to make it sleep. You can assume the sleep to some heavy load<br>
> work, like loop i from 0 to 10000000000. When multiple requests come in<br>
> concurrently, I saw the request is executed in sequence, not in parallel<br>
> (using yield gen.Task). But the old way of async_callback works.<br>
><br>
> How to use gen.Task to create async behavior?<br>
><br>
><br>
> On Wednesday, October 3, 2012 5:51:54 AM UTC+8, aliane abdelouahab wrote:<br>
>><br>
>> look here, maybe it will help:<br>
>><br>
>> <a href="http://groups.google.com/group/python-tornado/browse_thread/thread/ae9b7527bf3d8948" target="_blank">http://groups.google.com/<wbr>group/python-tornado/browse_<wbr>thread/thread/ae9b7527bf3d8948</a><br>
>><br>
>> On 2 oct, 11:08, Li jiaming <<a>li.jiam...@gmail.com</a>> wrote:<br>
>> > I created a simple app with gen.task. But seems doesn't work<br>
>> > asynchronously. I try to call /sleep for multiple times, but it handles<br>
>> > request in sequence.<br>
>> ><br>
>> > import tornado.ioloop<br>
>> > import tornado.web<br>
>> > from tornado.web import asynchronous<br>
>> > from tornado import gen<br>
>> > import time<br>
>> > import tornado.httpserver<br>
>> ><br>
>> > class MainHandler(tornado.web.<wbr>RequestHandler):<br>
>> > def get(self):<br>
>> > print 'receive root request'<br>
>> > self.write("Hello, world")<br>
>> ><br>
>> > class SleepHandler(tornado.web.<wbr>RequestHandler):<br>
>> > @asynchronous<br>
>> > @gen.engine<br>
>> > def get(self):<br>
>> > print 'receive sleep request'<br>
>> > yield [ gen.Task(self.sleep, 10),<br>
>> > gen.Task(self.sleep, 9)]<br>
>> > self.write("Wake up")<br>
>> > self.finish()<br>
>> ><br>
>> > def sleep(self, sec, callback):<br>
>> > print 'sleep for %d seconds' % sec<br>
>> > time.sleep(sec)<br>
>> > print 'finish sleep %d' % sec<br>
>> > return callback()<br>
>> ><br>
>> > application = tornado.web.Application([<br>
>> > (r"/", MainHandler),<br>
>> > (r"/sleep", SleepHandler),<br>
>> > ])<br>
>> ><br>
>> > if __name__ == "__main__":<br>
>> > server = tornado.httpserver.HTTPServer(<wbr>application)<br>
>> > server.listen(8888)<br>
>> > tornado.ioloop.IOLoop.<wbr>instance().start()<br>
>> ><br>
>> > *Anything wrong in my code?*<br>
>> ><br>
>> > I also tried async_callback (which is claimed to be obsoleted way of<br>
>> > doing<br>
>> > async). But it works. It can handle multiple requests in parallel when<br>
>> > calling /sleep.<br>
>> ><br>
>> > class SleepHandler(tornado.web.<wbr>RequestHandler):<br>
>> > @asynchronous<br>
>> > def get(self):<br>
>> > print 'receive sleep request'<br>
>> > self.async_callback(self.<wbr>callback_sleep, 10)<br>
>> ><br>
>> > def callback_sleep(self, sec):<br>
>> > print 'callback sleep for %d seconds' % sec<br>
>> > time.sleep(sec)<br>
>> > print 'finish callback sleep for %d seconds' % sec<br>
>> > self.write('wake up')<br>
>> > self.finish()<br>
</div></div></blockquote></div><br>
</div>
</blockquote></div>
------=_Part_641_15593101.1349318502077--
------=_Part_640_27727705.1349318502077--