threadlocals有什么坏处

时间:2009-12-17 07:29:09

标签: python django thread-local

Django世界中的每个人似乎都讨厌threadlocals(http://code.djangoproject.com/ticket/4280http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser)。我读过阿明的论文(http://lucumr.pocoo.org/2006/7/10/why-i-cant-stand-threadlocal-and-others),但大多数都取决于threadlocals是不好的,因为它不够优雅。

我有一个场景,其中thellocals将使事情变得更加容易。 (我有一个应用程序,人们将有子域名,因此所有模型都需要访问当前子域名,并且从请求中传递它们是不值得的,如果threadlocals的唯一问题是它们不优雅,或者变得脆弱代码。)

许多Java框架似乎也经常使用threadlocals,那么它们的情况与Python / Django的情况有何不同?

5 个答案:

答案 0 :(得分:22)

我避免使用threadlocals,因为它引入了一个隐式的非局部耦合。我经常以各种非面向HTTP的方式使用模型(本地管理命令,数据导入/导出等)。如果我访问models.py中的一些threadlocals数据,现在我必须找到一些方法来确保每当我使用我的模型时它总是被填充,这可能会非常难看。

在我看来,更明确的代码更清晰,更易于维护。如果模型方法需要子域才能运行,那么通过让该方法接受该子域作为参数,这一事实应该是显而易见的。

如果我绝对找不到在threadlocals中存储请求数据的方法,我至少会在一个单独的模块中实现包装器方法,该模块访问threadlocals并使用所需的数据调用模型方法。这样,models.py仍然是自包含的,模型可以在没有threadlocals耦合的情况下使用。

答案 1 :(得分:18)

我认为threadlocals没有任何问题 - 是的,它是一个全局变量,但除此之外它是一个普通的工具。我们仅仅为此目的使用它(在上下文中将子域模型存储到来自中间件的当前请求)并且它完美地工作。

所以我说,使用正确的工具,在这种情况下,threadlocals使你的应用程序比在所有模型方法中传递子域模型更优雅(没有提到它甚至不总是可能的事实 - 当你重写django管理器方法来限制子域的查询,你无法向get_query_set传递任何额外的东西,例如 - 所以threadlocals是自然而唯一的答案。)

答案 2 :(得分:3)

  

许多Java框架似乎也经常使用threadlocals,那么它们的情况与Python / Django的情况有何不同?

CPython的解释器有一个全局解释器锁(GIL),这意味着解释器在任何给定时间只能执行一个Python线程。我不清楚Python解释器实现是否需要使用多个操作系统线程才能实现这一点,尽管在实践中CPython确实如此。

Java的主要锁定机制是通过对象的监视器锁。这是一种分散的方法,允许在多核和/或多处理器CPU上使用多个并发线程,但也会产生更复杂的同步问题,供程序员处理。

这些同步问题仅出现在“共享可变状态”中。如果状态不可变,或者在ThreadLocal的情况下它不被共享,那么Java程序员就可以解决这个问题。

CPython程序员仍然需要处理竞争条件的可能性,但是一些更为深奥的Java问题(例如出版物)可能会被解释器解决。

CPython程序员还可以选择在Python可调用的C或C ++代码中编写性能关键代码,其中GIL限制不适用。从技术上讲,Java程序员通过JNI有类似的选择,但这在Java中被认为是正确或错误的,而不是Python。

答案 3 :(得分:2)

当您使用多个线程并希望将某些对象本地化为特定线程时,您希望使用threadlocals,例如。每个线程有一个数据库连接。 在您的情况下,您希望将其更多地用作全局上下文(如果我理解正确的话),这可能是一个坏主意。它会让你的应用程序变得更慢,更加耦合,更难以测试。

为什么从请求传递它不值得呢?为什么不将它存储在会话或用户配置文件中?

与Java不同的是,Web开发比Python / PERL / PHP / Ruby世界更有状态,因此人们习惯于所有类型的上下文和类似的东西。我不认为这是一个优势,但它在开始时似乎确实如此。

答案 4 :(得分:0)

我发现使用ThreadLocal是在HTTP请求/响应环境(即任何webapp)中实现依赖注入的一种很好的方法。您只需设置一个servlet过滤器,以便在接收请求时将所需对象“注入”到线程中,并在返回响应时“取消注释”它。

这是一个聪明人的DI没有所有的XML丑陋,没有Spring Jars的MB(更不用说它的学习曲线)而且没有所有神秘的重复@annotation废话,并且因为它没有单独注入许多对象实例依赖性它可能更快,并且使用更少的内存。

它工作得很好我们开源了我们的exPOJO Filter,可以使用ThreadLocal注入Hibernate会话或JDO PersistenceManager:

http://www.expojo.com