python“全局”(模块)变量是否为本地线程?

时间:2022-12-24 16:49:20

I'd like to use an in-memory thread-local cache for a value from the database that isn't going to change during a request/response cycle, but gets called hundreds (potentially thousands) of times. My limited understanding is that using a "global"/module variable is one way to implement this type of cache.

我想使用内存中的线程本地缓存来获取数据库中的值,该值在请求/响应周期中不会发生变化,但会被调用数百次(可能数千次)。我有限的理解是使用“全局”/模块变量是实现此类缓存的一种方法。

e.g.:

#somefile.py

foo = None

def get_foo(request):
  global foo
  if not foo:
    foo = get_foo_from_db(request.blah)
  return foo

I'm wondering whether using this type of "global" is thread-safe in python, and that therefore I can be comfortable that get_foo_from_db() will get called exactly once per request/response cycle in django (using either runserver or gunicorn+gevent). Is my understanding correct? This thing gets called enough that even using memcached to store the value is going to be a bottleneck (I'm profiling it as we speak).

我想知道在python中使用这种类型的“全局”是否是线程安全的,因此我很乐意在django中每个请求/响应周期调用get_foo_from_db()一次(使用runserver或gunicorn + gevent) )。我的理解是否正确?这个东西被充分调用,即使使用memcached来存储该值也将成为一个瓶颈(我在说话时对它进行分析)。

2 个解决方案

#1


3  

No, you are wrong on two counts.

不,你错了两点。

Firstly, the use of "threads" is a bit vague here. Depending on how its server is configured, Django can be served either using threads or processes or both (see the mod_wsgi documentation for a full discussion). If there is a single thread per process, then you can can guarantee that only one instance of a module will be available to each process. But that is highly dependent on that configuration.

首先,这里使用“线程”有点模糊。根据服务器的配置方式,可以使用线程或进程或两者来提供Django(有关完整讨论,请参阅mod_wsgi文档)。如果每个进程只有一个线程,那么您可以保证每个进程只能使用一个模块实例。但这在很大程度上取决于该配置。

Even so, it is still not the case that there will be "exactly one" call to that function per request/response cycle. This is because the lifetime of a process is entirely unrelated to that cycle. A process will last for multiple requests, so that variable will persist for all of those requests.

即便如此,仍然不是每个请求/响应周期对该功能进行“完全一次”调用的情况。这是因为过程的生命周期与该循环完全无关。进程将持续多个请求,因此变量将持续存在于所有这些请求中。

#2


3  

No, access to globals is not thread-safe. Threads do not get their own copy of globals, globals are shared among threads.

不,访问全局变量不是线程安全的。线程没有得到自己的全局变量,全局变量在线程之间共享。

The code:

if not foo:
    foo = get_foo_from_db(request.blah)

compiles to several python bytecode statements:

编译成几个python字节码语句:

  2           0 LOAD_FAST                1 (foo)
              3 POP_JUMP_IF_TRUE        24

  3           6 LOAD_GLOBAL              0 (get_foo_from_db)
              9 LOAD_FAST                0 (request)
             12 LOAD_ATTR                1 (blah)
             15 CALL_FUNCTION            1
             18 STORE_FAST               1 (foo)
             21 JUMP_FORWARD             0 (to 24)

A thread switch can occur after each and every bytecode execution, so another thread could alter foo after you tested it.

每次执行字节码后都会发生线程切换,因此在测试之后,另一个线程可能会改变foo。

#1


3  

No, you are wrong on two counts.

不,你错了两点。

Firstly, the use of "threads" is a bit vague here. Depending on how its server is configured, Django can be served either using threads or processes or both (see the mod_wsgi documentation for a full discussion). If there is a single thread per process, then you can can guarantee that only one instance of a module will be available to each process. But that is highly dependent on that configuration.

首先,这里使用“线程”有点模糊。根据服务器的配置方式,可以使用线程或进程或两者来提供Django(有关完整讨论,请参阅mod_wsgi文档)。如果每个进程只有一个线程,那么您可以保证每个进程只能使用一个模块实例。但这在很大程度上取决于该配置。

Even so, it is still not the case that there will be "exactly one" call to that function per request/response cycle. This is because the lifetime of a process is entirely unrelated to that cycle. A process will last for multiple requests, so that variable will persist for all of those requests.

即便如此,仍然不是每个请求/响应周期对该功能进行“完全一次”调用的情况。这是因为过程的生命周期与该循环完全无关。进程将持续多个请求,因此变量将持续存在于所有这些请求中。

#2


3  

No, access to globals is not thread-safe. Threads do not get their own copy of globals, globals are shared among threads.

不,访问全局变量不是线程安全的。线程没有得到自己的全局变量,全局变量在线程之间共享。

The code:

if not foo:
    foo = get_foo_from_db(request.blah)

compiles to several python bytecode statements:

编译成几个python字节码语句:

  2           0 LOAD_FAST                1 (foo)
              3 POP_JUMP_IF_TRUE        24

  3           6 LOAD_GLOBAL              0 (get_foo_from_db)
              9 LOAD_FAST                0 (request)
             12 LOAD_ATTR                1 (blah)
             15 CALL_FUNCTION            1
             18 STORE_FAST               1 (foo)
             21 JUMP_FORWARD             0 (to 24)

A thread switch can occur after each and every bytecode execution, so another thread could alter foo after you tested it.

每次执行字节码后都会发生线程切换,因此在测试之后,另一个线程可能会改变foo。