Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
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&nbsp;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">&lt;<a href="javascript:" target="_blank" gdf-obfuscated-mailto="xuL5JSSKTIwJ">b...@bendarnell.com</a>&gt;</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. &nbsp;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. &nbsp;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: &nbsp;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. &nbsp;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. &nbsp;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 &lt;<a href="javascript:" target="_blank" gdf-obfuscated-mailto="xuL5JSSKTIwJ">li.ji...@gmail.com</a>&gt; wrote:<br>
&gt; I don't mean to make it sleep. You can assume the sleep to some heavy load<br>
&gt; work, like loop i from 0 to 10000000000. When multiple requests come in<br>
&gt; concurrently, I saw the request is executed in sequence, not in parallel<br>
&gt; (using yield gen.Task). But the old way of async_callback works.<br>
&gt;<br>
&gt; How to use gen.Task to create async behavior?<br>
&gt;<br>
&gt;<br>
&gt; On Wednesday, October 3, 2012 5:51:54 AM UTC+8, aliane abdelouahab wrote:<br>
&gt;&gt;<br>
&gt;&gt; look here, maybe it will help:<br>
&gt;&gt;<br>
&gt;&gt; <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>
&gt;&gt;<br>
&gt;&gt; On 2 oct, 11:08, Li jiaming &lt;<a>li.jiam...@gmail.com</a>&gt; wrote:<br>
&gt;&gt; &gt; I created a simple app with gen.task. But seems doesn't work<br>
&gt;&gt; &gt; asynchronously. I try to call /sleep for multiple times, but it handles<br>
&gt;&gt; &gt; request in sequence.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; import tornado.ioloop<br>
&gt;&gt; &gt; import tornado.web<br>
&gt;&gt; &gt; from tornado.web import asynchronous<br>
&gt;&gt; &gt; from tornado import gen<br>
&gt;&gt; &gt; import time<br>
&gt;&gt; &gt; import tornado.httpserver<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; class MainHandler(tornado.web.<wbr>RequestHandler):<br>
&gt;&gt; &gt; &nbsp; &nbsp; def get(self):<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; print 'receive root request'<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; self.write("Hello, world")<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; class SleepHandler(tornado.web.<wbr>RequestHandler):<br>
&gt;&gt; &gt; &nbsp; &nbsp; @asynchronous<br>
&gt;&gt; &gt; &nbsp; &nbsp; @gen.engine<br>
&gt;&gt; &gt; &nbsp; &nbsp; def get(self):<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; print 'receive sleep request'<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; yield [ gen.Task(self.sleep, 10),<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gen.Task(self.sleep, 9)]<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; self.write("Wake up")<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; self.finish()<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; &nbsp; &nbsp; def sleep(self, sec, callback):<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; print 'sleep for %d seconds' % sec<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; time.sleep(sec)<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; print 'finish sleep %d' % sec<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; return callback()<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; application = tornado.web.Application([<br>
&gt;&gt; &gt; &nbsp; &nbsp; (r"/", MainHandler),<br>
&gt;&gt; &gt; &nbsp; &nbsp; (r"/sleep", SleepHandler),<br>
&gt;&gt; &gt; ])<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; if __name__ == "__main__":<br>
&gt;&gt; &gt; &nbsp; &nbsp; server = tornado.httpserver.HTTPServer(<wbr>application)<br>
&gt;&gt; &gt; &nbsp; &nbsp; server.listen(8888)<br>
&gt;&gt; &gt; &nbsp; &nbsp; tornado.ioloop.IOLoop.<wbr>instance().start()<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; *Anything wrong in my code?*<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; I also tried async_callback (which is claimed to be obsoleted way of<br>
&gt;&gt; &gt; doing<br>
&gt;&gt; &gt; async). But it works. It can handle multiple requests in parallel when<br>
&gt;&gt; &gt; calling /sleep.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; class SleepHandler(tornado.web.<wbr>RequestHandler):<br>
&gt;&gt; &gt; &nbsp; &nbsp; @asynchronous<br>
&gt;&gt; &gt; &nbsp; &nbsp; def get(self):<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; print 'receive sleep request'<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; self.async_callback(self.<wbr>callback_sleep, 10)<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; &nbsp; &nbsp; def callback_sleep(self, sec):<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; print 'callback sleep for %d seconds' % sec<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; time.sleep(sec)<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; print 'finish callback sleep for %d seconds' % sec<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; self.write('wake up')<br>
&gt;&gt; &gt; &nbsp; &nbsp; &nbsp; &nbsp; self.finish()<br>
</div></div></blockquote></div><br>
</div>
</blockquote></div>
------=_Part_641_15593101.1349318502077--

------=_Part_640_27727705.1349318502077--