WSGI:使每个请求真正独一无二

时间:2012-04-06 22:16:28

标签: python mod-wsgi wsgi

我目前正在熟悉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()

2 个答案:

答案 0 :(得分:1)

此答案基于@ user590028答案评论中提出的新信息。

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

  

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

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

更新

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

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

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

答案 1 :(得分:0)

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

之类的东西
相关问题