简体   繁体   中英

Share state between threads in bottle

In my Bottle app running on pythonanywhere , I want objects to be persisted between requests.

If I write something like this:

X = {'count': 0}

@route('/count')
def count():
    X['count'] += 1
    tpl = SimpleTemplate('Hello {{count}}!')
    return tpl.render(count=X['count'])

The count increments, meaning that X persists between requests.

I am currently running this on pythonanywhere , which is a managed service where I have no control over the web server (nginx I presume?) threading, load balancing (if any) etc...

My question is, is this coincidence because it's only using one thread while on minimal load from me doing my tests?

More generally, at which point will this stop working? Eg I have more than one thread/socket/instance/load-balanced server etc...?

Beyond that, what is my best options to make something like this work (sticking to Bottle) even if I have to move to a barebones server.

Here's what Bottle docs have to say about their request object:

A thread-safe instance of LocalRequest. If accessed from within a request callback, this instance always refers to the current request (even on a multi-threaded server).

But I don't fully understand what that means, or where global variables like the one I used stand with regards to multi-threading.

TL;DR: You'll probably want to use an external database to store your state.

If your application is tiny, and you're planning to always have exactly one server process running, then your current approach can work; "all" you need to do is acquire a lock around every (!) access to the shared state (the dict X in your sample code). (I put "all" in scare quotes there because it's likely to become more complicated than it sounds at first.)

But, since you're asking about multithreading, I'll assume that your application is more than a toy, meaning that you plan to receive substantial traffic and/or want to handle multiple requests concurrently. In this case, you'll want multiple processes, which means that your approach--storing state in memory--cannot work. Memory is not shared across processes. The (general) way to share state across processes is to store the state externally, eg in a database.

Are you familiar with Redis? That'd be on my short list of candidates.

I go the answers by contacting PythonAnywhere support, who had this to say:

When you run a website on a free PythonAnywhere account, just one process handles all of your requests -- so a global variable like the one you use there will be fine. But as soon as you want to scale up, and get (say) a hacker account, then you'll have multiple processes (not, not threads) -- and of course each one will have its own global variables, so things will go wrong.

So that part deals with the PythonAnywhere specifics on why it works, and when it would stop working on there.

The answer to the second part, about how to share variables between multiple Bottle processes, I also got from their support (most helpful!) once they understood that a database would not work well in this situation.

Different processes cannot of course share variables, and the most viable solution would be to:

write your own kind of caching server to handle keeping stuff in memory [...] You'd have one process that ran all of the time, and web API requests would access it somehow (an internal REST API?). It could maintain stuff in memory [...]

Ps: I didn't expect other replies to tell me to store state in a database, I figured that the fact I'm asking this means I have a good reason not to use a database, apologies for time wasted!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM