1

我目前正在熟悉 Python 中 Web 应用程序的 WSGI 规范。我设置 Apache(使用 mod-wsgi)来调用一个小应用程序,该应用程序当前只显示线程 ID 号,以尝试观察每个请求的唯一性:

import thread

def application(environ, start_response)
    start_response('200 Ok', [('Content-type', 'text/plain')])
    output = "current thread id: %s" % thread.get_ident()
    return [output]

我很快注意到,过了一会儿,后续请求会重用相同的线程。

如果我的理解是正确的,为了让我的应用程序具有“特定于上下文”的变量,我需要使用类似于以下的方案来存储它们:

lock = thread.allocate_lock()
lock.acquire()
thread_id = get_ident()
threadsafe[thread_id]['user'] = request.username
lock.release()

然后我可以以类似的方式从应用程序的不同部分访问它们。在这种情况下,我唯一的保证是该值属于该特定线程。然而,使用同一个线程的请求可能仍然会踩到对方的脚趾(例如,请求访问来自先前请求的剩余值)。我的结论是,要以真正独特的方式处理每个请求,除了“thread_id”之外,我还需要另一个键来区分使用同一线程的请求。

使用 uuid 之类的唯一键,我可以做到这一点

lock.acquire()
uuid = uuid.uuid4()
thread_id = get_ident()
threadsafe[(thread_id, uuid)]['user'] = request.username
lock.release()

但这意味着我也有办法以线程安全的方式检索 uuid 值,就像我以后可以检索 thread_id 一样。

我得出了正确的结论吗?如果是这样,我如何获得该附加密钥?

编辑

我突然想到我的问题是错误的二分法。我以线程可以与自身同时运行的观点来处理事情,而实际上这是不可能的。使用同一线程的请求必须串行运行。因此,我实际上可以使用 uuid 来避免使用线程的陈旧值,但只有在将其存储为线程保存值本身之后。

# somewhere early in the request
threadsafe[thread_id]['current_uuid'] = uuid.uuid4()

# later
lock.acquire()
thread_id = get_ident()
uuid = threadsafe[thread_id]['current_uuid']
threadsafe[(thread_id, uuid)]['user'] = request.username
lock.release()
4

2 回答 2

1

该答案基于@user590028 答案的评论中开发的新信息。

您说您的目标是拥有线程安全的持久数据。因为您还说您正在熟悉 WSGI 规范,所以我觉得这个链接特别相关:Application_Global_Variables

...虽然可以使用全局数据,但它只能用于缓存可以在该单个进程的上下文中安全重用的数据。您不能使用全局数据作为保存任何请求处理程序必须可见的信息的手段,无论它在哪个进程中运行。

您的应用程序可能不仅在多个线程下运行,而且可能在多个进程下运行。根据上面的链接,对于持久数据(超出当前请求)的推荐解决方案是使用外部存储解决方案(文件系统、数据库、memcached ......)

更新

你试图用锁来保存状态信息似乎完全没有必要。无论如何,每个请求都应该被认为是唯一的。如果客户端用户向您的应用程序发出 10 个请求,并且您希望在这些请求中保留数据,那么您应该使用会话密钥(如 cookie),当他们的请求是新的(不包含会话)时您首先向客户端建立,然后您在响应中返回它并期望将来的请求提供此密钥。随后,有一些库旨在为您提供此功能:http ://www.ollycope.com/software/pesto/session.html

wsgi 应用程序有一个入口点,在这种情况下,您的示例将其定义为一个名为“应用程序”的函数。它也可能是一个类或任何可调用的东西。由于范围,您的变量本质上是特定于上下文的。无论您对该范围做什么,都与运行同一处理程序的任何其他线程完全不同。“应用程序”函数可能更复杂,调用其他函数并传递其变量,直到最终返回其响应体。您还可以创建一个类实例,其中包含处理请求和生成响应所需的所有功能,并使用它自己的实例变量。

如果前两个建议都不适用于您的要求,我认为唯一剩下的可能性是您确实希望将数据存储在数据库、文件系统、memcached 或 redis 等中。uuid4 将是唯一的,但它的值只有在您在响应中传递它并让客户端返回它以保持与该数据的关联时才有意义。

于 2012-04-06T23:18:33.400 回答
0

你说的对。线程 id 不保证随着时间的推移是唯一的。考虑 UUID。像 str(uuid.uuid4()) 这样的东西

于 2012-04-06T22:22:55.127 回答