CherryPy, Threads, and Member Variables; potential

2020-07-25 20:38发布

问题:

Let's say I have the following simple class:

import cherrypy
import os

class test:
  test_member = 0;
  def __init__(self):
    return
  def index(self):
    self.test_member = self.test_member + 1
    return str(self.test_member)
  index.exposed = True

conf = os.path.join(os.path.dirname(__file__), 'config.ini')

if __name__ == '__main__':
  # CherryPy always starts with app.root when trying to map request URIs
  # to objects, so we need to mount a request handler root. A request
  # to '/' will be mapped to HelloWorld().index().
  cherrypy.config.update({'server.socket_host': '0.0.0.0'})
  cherrypy.quickstart(test(), config=conf)
else:
  # This branch is for the test suite; you can ignore it.
  cherrypy.config.update({'server.socket_host': '0.0.0.0'})
  cherrypy.tree.mount(test(), config=conf)

So when I open my index page the first time I get back 1, the next time 2, then 3, 4, and so on. My questions are:

  • Are there any big dangers with this, particularly with threads and multiple people accessing the page at the same time?
  • Do I have to lock the member variable in some way each time it's written to in order to prevent issues?
  • Does anything change if I'm using a none basic data type as a member (such as my own, complicated class) rather than something as simple as an integer?

I don't totally understand how threading with CherryPy works, I suppose my concern in this simple example would be that on one thread the test_member could be equal to one thing, and when accessed from another thread it'd be something totally different. I apologize in advance if I'm missing something that's well documented, but some googling didn't really turn up what I was looking for. I understand for such a simple example there are a number of relatively easy paths that could solve potential problems here (keep the state of the variable in a database, or something along those lines), but that won't work in my actual use case.

回答1:

There's a danger there of lost updates. Just setting the value shouldn't need to lock, since replacing an instance variable is atomic with respect to the GIL (assuming it doesn't call any special methods, etc). But incrementing or using more complex variables will need different schemes to make them threadsafe.

Shared access in CherryPy is generally no different than any other Python program. Rather than a long rehash of all those options here, it's best to direct you to http://effbot.org/zone/thread-synchronization.htm As it mentions, replacing an instance variable is probably atomic with respect to the GIL and thereby thread-safe, but incrementing is not.

CherryPy only adds some helpers in the opposite direction: when you don't want to share: the cherrypy.request and cherrypy.response objects are newly created (and properly destroyed) for each request/response--feel free to stick data in cherrypy.request.foo if you want to keep it around for the duration of the request only.