Python Tornado - starting POST immediately when the asynchronous access function works

so I have a handler below:

class PublishHandler(BaseHandler): def post(self): message = self.get_argument("message") some_function(message) self.write("success") 

The problem that I am facing is that some_function () takes some time to execute, and I would like the post request to be returned immediately when called and for some_function () to be executed in another thread / process, if possible.

I use berkeley db as a database, and what I'm trying to do is relatively simple.

I have a user database with a filter. If the filter matches the message, the server will send a message to the user. I am currently testing thousands of users, and therefore, every time I post a message through an email request, it iterates through thousands of users to find a match. This is my naive implementation of affairs and, therefore, my question. How can I do it better?

+6
python tornado
source share
2 answers

You may be able to accomplish this using your IOLoop add_callback method:

 loop.add_callback(lambda: some_function(message)) 

Tornado will call back in the following IOLoop protocol, which can (I would have to dig out the guts of Tornado to know exactly or, conversely, test it) to allow the request before this code is executed.

The downside is that this long code that you wrote still takes time to execute, and this may block another request. This is not ideal if you have a lot of these queries right away.

A more robust solution is to run it in a separate thread or process. The best way with Python is to use the process because of the GIL (I would highly recommend reading about it if you are not familiar with it). However, on a single processor machine, the streaming implementation will work just as well and it may be easier to implement.

If you are following a stream route, you can create a nice "async executor" module with a mutex, stream, and queue. Check out the multiprocessing module if you want to follow the path of using a separate process.

+7
source share

I tried this, and I believe the request does not complete until the callbacks are called.

I think a dirty hack will call two add_callback levels, for example:

  def get(self): ... def _defered(): ioloop.add_callback(<whatever you want>) ioloop.add_callback(_defered) ... 

But at best, these are hacks. I'm looking for a better solution right now, probably ending with some message queue or simple stream solution.

+1
source share

All Articles