please help with ioloop and threading "one ioloop per thread"

1,282 views
Skip to first unread message

CODEY

unread,
Nov 8, 2012, 9:26:49 PM11/8/12
to python-...@googlegroups.com
I have a server heating up and dying, and it seems to be KeyError: 9L in ioloop ... I read somewhere after following some posts that maybe i am doing something that is not thread safe ... 

Here is what I have .. 


application = tornado.web.Application([
(r"/", MainHandler),
])


if __name__ == "__main__":
import os
port = 8080

application.listen(port)
ioloop = tornado.ioloop.IOLoop.instance()
ioloop.start()
print "ended"


Now, in mainhandler i have something like this: 

class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def post(self):
              self.set_header(... bunch of headers ... )
                s = MyClass()
s.sObj = self
s.start()

Now the MyClass is like this: 

class MyClass(threading.Thread):
def run(self):
handleStuff(self.sObj)

where self.finish() is called at the end of handleStuff() ... 


So ... anything wrong yet?  The applications runs fine ... but I am having some crashing going on .... i saw somewhere i should be using a callback somewhere, and someone using "one ioloop per thread" ... but i am not sure where or how i do this .. .please help

CODEY

unread,
Nov 8, 2012, 10:21:17 PM11/8/12
to python-...@googlegroups.com
also please let me know if there is any inherent problem in all this so i can understand ... seems ok to me, but i do not understand the ioloop well enough .. i think the way i am setting it up i have one ioloop and multiple threads ... how can i make one ioloop per thread ?

CODEY

unread,
Nov 8, 2012, 10:28:00 PM11/8/12
to python-...@googlegroups.com
in case you are wondering, i need threads because i have long running processes kicking off on each request ... i cannot block one user when there are 100 others waiting

Serge S. Koval

unread,
Nov 9, 2012, 2:43:27 AM11/9/12
to python-...@googlegroups.com
You can use threads, but you can not use Tornado API from threads.

When you have something to send, you have to switch to main thread using ioloop.add_callback. Callback will be executed in context of main thread and you're free to use Tornado API. Example:

def process(data):
    # ... do something
    def send():
        conn.write(result)
        conn.finish()

    ioloop.add_callback(send)

Serge.    

CODEY

unread,
Nov 9, 2012, 7:44:34 PM11/9/12
to python-...@googlegroups.com
thank you. ..i found this online, i think it is fixed now: 

import functools
import time
import threading
import logging

import tornado.web
import tornado.websocket
import tornado.locale
import tornado.ioloop

class Handler(tornado.web.RequestHandler):
    def perform(self, callback):
        #do something cuz hey, we're in a thread!
        time.sleep(5)
        output = 'foo'
        tornado.ioloop.IOLoop.instance().add_callback(functools.partial(callback, output))

    def initialize(self):
        self.thread = None

    @tornado.web.asynchronous
    def get(self):
        self.thread = threading.Thread(target=self.perform, args=(self.on_callback,))
        self.thread.start()

        self.write('In the request')
        self.flush()

    def on_callback(self, output):
        logging.info('In on_callback()')
        self.write("Thread output: %s" % output)
        self.finish()

application = tornado.web.Application([
    (r"/", Handler),

])

if __name__ == "__main__":

    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

Russ Weeks

unread,
Nov 9, 2012, 8:04:39 PM11/9/12
to python-...@googlegroups.com
The way you have it set up right now, you'll create a new thread to service each request.  Probably better to use a thread pool to cap the number of active threads.

I've found the stdlib's multiprocessing.pool.ThreadPool to be very easy to use.  Set it up like this:

tp = ThreadPool(num_threads)

Then instead of creating and starting a new thread, do:

tp.apply(lambda:self.perform(self.on_callback))

The thread pool uses a task queue, so even if all threads are busy your request handler won't block waiting for a thread to become available.

-Russ 

aliane abdelouahab

unread,
Nov 10, 2012, 7:10:00 AM11/10/12
to Tornado Web Server
i've asked a question and dident get the answer:
http://stackoverflow.com/questions/13219805/why-do-people-talk-about-threading-when-using-tornado
there is GIL, but everyone talks about threads?

On 10 nov, 02:04, Russ Weeks <rwe...@newbrightidea.com> wrote:
> The way you have it set up right now, you'll create a new thread to service
> each request.  Probably better to use a thread pool to cap the number of
> active threads.
>
> I've found the stdlib's multiprocessing.pool.ThreadPool to be very easy to
> use.  Set it up like this:
>
> tp = ThreadPool(num_threads)
>
> Then instead of creating and starting a new thread, do:
>
> tp.apply(lambda:self.perform(self.on_callback))
>
> The thread pool uses a task queue, so even if all threads are busy your
> request handler won't block waiting for a thread to become available.
>
> -Russ
>
>
>
>
>
>
>
> On Fri, Nov 9, 2012 at 4:44 PM, CODEY <ed.pat...@gmail.com> wrote:
> > thank you. ..i found this online, i think it is fixed now:
>
> > import functoolsimport timeimport threadingimport logging
> > import tornado.webimport tornado.websocketimport tornado.localeimport tornado.ioloop
> > class Handler(tornado.web.RequestHan**dler):
> >     def perform(self, callback):
> >         #do something cuz hey, we're in a thread!
> >         time.sleep(5)
> >         output = 'foo'
> >         tornado.ioloop.IOLoop.instance**().add_callback(functools.part**ial(callbac k, output))
>
> >     def initialize(self):
> >         self.thread = None
>
> >     @tornado.web.asynchronous
> >     def get(self):
> >         self.thread = threading.Thread(target=self.p**erform, args=(self.on_callback,))
> >         self.thread.start()
>
> >         self.write('In the request')
> >         self.flush()
>
> >     def on_callback(self, output):
> >         logging.info('In on_callback()')
> >         self.write("Thread output: %s" % output)
> >         self.finish()
>
> > application = tornado.web.Application([
> >     (r"/", Handler),
> > ])
> > if __name__ == "__main__":
>
> >     application.listen(8888)
> >     tornado.ioloop.IOLoop.instance**().start()
Reply all
Reply to author
Forward
0 new messages