Django会话线程安全吗?

9 投票
5 回答
4550 浏览
提问于 2025-04-17 06:45

我在Django的会话中存储了一个字典,这个字典可以被多个线程访问。所有线程都可以更新这个字典,同时也会从字典中获取值来运行程序。我想知道Django的会话是否是线程安全的,还是说我需要使用锁或者信号量来保护它?

举个典型的例子:

Thread1:
threadDict = request.session.get('threadDict', None)
if threadDict['stop']:
   #break the for loop exit the thread
else:
   #do some processing and update some values in thread dictionary
   threadDict['abc'] = 0
   request.session['threadDict'] = threadDict (Point1)

def someFunction():
    #this function is used to send stop signal to thread
    threadDict = request.session.get('threadDict', None)
    threadDict['stop'] = True
    request.session['threadDict'] = threadDict (Point2)

假设在Point2更新会话中的字典之后,Point1也更新了字典,这样我的stop指令可能就会丢失。

更多信息

一个ajax请求启动了四个线程,这些线程从四个不同的URL下载样本。为什么我使用线程呢?因为我想让用户看到哪些样本正在下载,哪些还没下载。所有线程都会在会话中的字典里更新它们的状态。线程启动后,我每两秒发一次ajax请求,从会话中获取字典并读取线程的当前状态。但是这个想法失败了,因为线程是独立于请求和它们的会话的。每个ajax请求肯定有自己的会话,但我不能把这个会话传递给线程,因为一旦线程开始,它们就和外界无关了(也许我可以传递,但可能没办法像线程处理得那么快)。所以为了处理这个问题,我选择了缓存框架而不是会话,因为缓存可以从任何地方访问。线程把它们的状态存储在字典中,然后放回缓存,每两秒我就从缓存中获取字典并读取状态。另外,根据我的经验,缓存不是线程安全的。因此,我为四个线程分别使用了四个字典。

5 个回答

0

我不太确定Django是否是线程安全的。举个例子,如果你用Apache和mod_wsgi配置,并且每个进程有多个线程,那么django/core/urlresolvers.py这个文件就不是线程安全的。不过他们正在努力解决这个问题。在Django的故障跟踪系统里,有一些相关的记录,像这个15849

2

Django的会话其实就是一个字典,它在请求处理开始时被获取,然后在处理结束时再保存回去 [来源]。所以,如果你同时对这个字典进行修改,那么最终只有一个修改会生效。不过通常情况下,普通用户是不会同时进行这样的操作的,业务也就照常进行。

现在,我不是很明白你的例子,但看起来你是在试图不当使用这个会话字典。我开发过不少基于Django的网站,也遇到过一些与Django本身的限制或bug有关的问题,但从多个线程同时操作会话字典在我看来就是一个典型的错误用法。

也许当你多说一些你想要实现的目标时,我们能找到解决方案?

9

每次请求返回的 request.session 对象都是一个新的,但它们会访问同样的存储空间。而且,这些数据会在请求时从存储中加载,在响应时再保存回去。所以,如果你想把一个长时间运行的线程中的信息转移到另一个请求中,你需要手动把它保存到这个长时间运行的线程里。不幸的是,这样做可能会导致对同一个会话数据的修改丢失。

从某种意义上说,会话是线程安全的。这样做不会让解释器崩溃。你的请求在第一次访问时会看到会话数据的一个快照,而在保存时会覆盖自那时以来的所有更改。所以会话的状态会保持一致,但某些请求的修改可能会丢失。

其实,这种特性在几乎所有框架中都是常见的——任何会话、缓存或其他可能在多个进程之间共享的存储,都不太可能在不覆盖其他人修改的情况下提供内部对象的修改。

撰写回答