9

我将字典存储在可由多个线程访问的 Django 会话中。所有线程都可以更新该字典,线程还从字典中获取值以运行进程。我想知道 Django Session 是线程安全的还是我必须使用锁或信号量?

典型例子:

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 请求启动四个线程,这些线程从 4 个不同的 url 下载样本。为什么我使用线程?因为我想向用户显示当前正在下载哪些样本以及剩下哪些样本。所有线程都将在会话中更新其字典中的状态。线程启动后,我每两秒发出一次 ajax 请求,并从会话中获取字典并读取线程的当前状态。但是这个想法失败了,因为线程独立于请求及其会话。每个 ajax 请求肯定都有它的会话,但我不能将该会话传递给线程,因为当它们一旦开始时,它们就独立于世界其他地方(也许我可以传递它,但我可能无法以最快的速度传递它,处理正在由线程)。所以为了解决这个问题,我选择缓存框架而不是会话。因为缓存可以从任何地方访问。线程将它们的状态存储在字典中并放回缓存中,每两秒我从缓存中取出字典并读取状态。根据我的经验,还有一件事缓存不是线程安全的。所以对于四个线程,我分别使用了四个字典。

4

5 回答 5

9

返回的request.session对象将是每个请求的新对象,访问相同的存储。此外,它们在请求时从存储中加载,并在响应时保存回来。因此,如果您希望将信息从长时间运行的线程传输到另一个请求,则需要手动将其保存在长时间运行的线程中。不幸的是,这将导致对同一会话数据的修改丢失。

会话在某种意义上是线程安全的。您不会以这种方式破坏解释器。您的请求将在第一次访问时将会话数据视为其快照,并且在保存时将覆盖自那一刻起发生的所有更改。所以会话状态会是一致的,但是一些请求的修改可能会丢失。

实际上,这个属性对于几乎任何框架都是常见的——任何可能在多个进程之间共享的会话/缓存/一些其他存储都不太可能提供对存储在其中的对象的修改,而不会覆盖某人的更改。

于 2011-12-18T11:54:24.907 回答
2

Django session 是在请求​​处理开始时获取并在结束时保存回来的字典 [ source ]。因此,如果您对其执行并行更改,那么其中一项更改将占上风。但通常人类用户不能执行这样的并行操作,业务就这样继续下去。

现在,我不太明白你的例子,但看起来你只是想滥用会话字典。我已经开发了很多基于 Django 的网站,我遇到了一些与 Django 本身内部的限制或错误相关的问题,但仍然搞乱来自多个线程的会话字典在我看来就像一个教科书示例滥用会话..

当你写更多关于你想要实现的东西时,也许我们可以找出解决方案?

于 2011-12-19T02:34:26.150 回答
0

我不确定 django 是线程安全的。例如 django/core/urlresolvers.py 不是线程安全的,如果你使用 Apache+mod_wsgi 配置,每个进程有多个线程。但他们努力做到这一点。一些票在 django 票务系统上15849

于 2011-11-29T22:49:49.177 回答
-1

由于全局解释器锁,Python 中的基本类型通常是线程安全的。在某些情况下(例如在执行 I/O 时)会释放此锁以允许其他线程访问。这意味着您(应用程序)必须在可能释放 GIL 的调用之间保持一致的状态。此类方法的示例是阻塞套接字操作。

于 2011-11-21T13:27:35.190 回答
-1

正如@Krumelur 所提到的,由于全局interpeter lock (GIL),Python 线程不会同时运行——这是一个缺陷,而不是一个特性,所以不要依赖它。

当前的解决方法是使用multiprocessing 模块创建子流程。您可以使用 Process 实例的 is_alive() 函数检查子进程是否正在运行。有关详细信息,请参阅文档。

于 2011-12-23T06:59:14.240 回答