threadlocals 有什么不好的地方
Django 世界中的每个人似乎都讨厌 threadlocals(http://code.djangoproject.com/ticket/4280,http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser)。我读了阿明关于此的文章(http: //lucumr.pocoo.org/2006/7/10/why-i-cant-stand-threadlocal-and-others),但大部分都取决于线程局部性,这很糟糕,因为它不优雅。
我有一个场景,adlocals 会让事情变得更加容易。 (我有一个应用程序,人们将拥有子域,因此所有模型都需要访问当前子域,并且如果线程本地的唯一问题是它们不优雅或变得脆弱,那么从请求传递它们是不值得的代码。)
此外,很多 Java 框架似乎都大量使用 threadlocals,那么它们的情况与 Python/Django 的情况有何不同?
Everybody in Django world seems to hate threadlocals(http://code.djangoproject.com/ticket/4280, http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser). I read Armin's essay on this(http://lucumr.pocoo.org/2006/7/10/why-i-cant-stand-threadlocal-and-others), but most of it hinges on threadlocals is bad because it is inelegant.
I have a scenario where theadlocals will make things significantly easier. (I have a app where people will have subdomains, so all the models need to have access to the current subdomain, and passing them from requests is not worth it, if the only problem with threadlocals is that they are inelegant, or make for brittle code.)
Also a lot of Java frameworks seem to be using threadlocals a lot, so how is their case different from Python/Django 's?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我避免使用线程局部变量,因为它引入了隐式非局部耦合。我经常以各种非面向 HTTP 的方式使用模型(本地管理命令、数据导入/导出等)。如果我访问 models.py 中的一些线程局部数据,现在我必须找到某种方法来确保每当我使用模型时它总是被填充,这可能会变得非常难看。
在我看来,更明确的代码更干净且更易于维护。如果模型方法需要子域才能运行,则应通过让该方法接受该子域作为参数来使这一事实变得明显。
如果我绝对找不到在线程局部变量中存储请求数据的方法,我至少会在一个单独的模块中实现包装方法,该模块访问线程局部变量并使用所需的数据调用模型方法。这样,models.py 保持独立,并且可以在没有线程局部耦合的情况下使用模型。
I avoid this sort of usage of threadlocals, because it introduces an implicit non-local coupling. I frequently use models in all kinds of non-HTTP-oriented ways (local management commands, data import/export, etc). If I access some threadlocals data in models.py, now I have to find some way to ensure that it is always populated whenever I use my models, and this could get quite ugly.
In my opinion, more explicit code is cleaner and more maintainable. If a model method requires a subdomain in order to operate, that fact should be made obvious by having the method accept that subdomain as a parameter.
If I absolutely could find no way around storing request data in threadlocals, I would at least implement wrapper methods in a separate module that access threadlocals and call the model methods with the needed data. This way the models.py remains self-contained and models can be used without the threadlocals coupling.
我不认为 threadlocals 有什么问题 - 是的,它是一个全局变量,但除此之外它是一个普通的工具。我们仅将其用于此目的(将子域模型存储在中间件当前请求的全局上下文中)并且它运行得很好。
所以我说,使用正确的工具来完成工作,在这种情况下,threadlocals 使您的应用程序比在所有模型方法中传递子域模型更加优雅(更不用说它甚至并不总是可能的事实 - 当您覆盖 django 时)管理器方法来限制子域的查询,例如,您无法将任何额外的内容传递给 get_query_set - 所以 threadlocals 是自然且唯一的答案)。
I don't think there is anything wrong with threadlocals - yes, it is a global variable, but besides that it's a normal tool. We use it just for this purpose (storing subdomain model in the context global to the current request from middleware) and it works perfectly.
So I say, use the right tool for the job, in this case threadlocals make your app much more elegant than passing subdomain model around in all the model methods (not mentioning the fact that it is even not always possible - when you are overriding django manager methods to limit queries by subdomain, you have no way to pass anything extra to get_query_set, for example - so threadlocals is the natural and only answer).
CPython 的解释器有一个全局解释器锁(GIL),这意味着解释器在任何给定时间只能执行一个 Python 线程。我不清楚 Python 解释器实现是否一定需要使用多个操作系统线程来实现这一目标,尽管实际上 CPython 确实如此。
Java 的主要锁定机制是通过对象的监视器锁。这是一种分散的方法,允许在多核和/或多处理器 CPU 上使用多个并发线程,但也会产生程序员需要处理的更复杂的同步问题。
这些同步问题仅在“共享可变状态”时出现。如果状态不可变,或者就像 ThreadLocal 的情况一样,它不是共享的,那么对于 Java 程序员来说,这是一个不太复杂的问题。
CPython 程序员仍然必须处理竞争条件的可能性,但一些更深奥的 Java 问题(例如发布)大概可以由解释器解决。
CPython 程序员还可以选择使用 Python 可调用的 C 或 C++ 代码来编写性能关键代码,其中 GIL 限制不适用。从技术上讲,Java 程序员可以通过 JNI 进行类似的选择,但无论正确还是错误,这在 Java 中都被认为比在 Python 中更难以接受。
CPython's interpreter has a Global Interpreter Lock (GIL) which means that only one Python thread can be executed by the interpreter at any given time. It isn't clear to me that a Python interpreter implementation would necessarily need to use more than one operating system thread to achieve this, although in practice CPython does.
Java's main locking mechanism is via objects' monitor locks. This is a decentralized approach that allows the use of multiple concurrent threads on multi-core and or multi-processor CPUs, but also produces much more complicated synchronization issues for the programmer to deal with.
These synchronization issues only arise with "shared-mutable state". If the state isn't mutable, or as in the case of a ThreadLocal it isn't shared, then that is one less complicated problem for the Java programmer to solve.
A CPython programmer still has to deal with the possibility of race conditions, but some of the more esoteric Java problems (such as publication) are presumably solved by the interpreter.
A CPython programmer also has the option to code performance critical code in Python-callable C or C++ code where the GIL restriction does not apply. Technically a Java programmer has a similar option via JNI, but this is rightly or wrongly considered less acceptable in Java than in Python.
当您使用多个线程并希望将某些对象本地化到特定线程时,您需要使用线程本地化,例如。每个线程有一个数据库连接。
就您而言,您希望更多地将其用作全局上下文(如果我理解正确的话),这可能是一个坏主意。它会让你的应用程序变得更慢、耦合性更强并且更难测试。
为什么从请求中传递它不值得?为什么不将其存储在会话或用户配置文件中?
与 Java 的区别在于,Web 开发比 Python/PERL/PHP/Ruby 世界更有状态,因此人们习惯了各种上下文和类似的东西。我不认为这是一个优势,但一开始看起来确实如此。
You want to use threadlocals when you're working with multiple threads and want to localize some objects to a specific thread, eg. having one database connection for each thread.
In your case, you want to use it more as a global context (if I understand you correctly), which is probably a bad idea. It will make your app a bit slower, more coupled and harder to test.
Why is passing it from request not worth it? Why don't you store it in session or user profile?
There difference with Java is that web development there is much more stateful than in Python/PERL/PHP/Ruby world so people are used to all kind of contexts and stuff like that. I don't think that is an advantage, but it does seem like it at the beginning.
我发现使用 ThreadLocal 是在 HTTP 请求/响应环境(即任何 Web 应用程序)中实现依赖注入的绝佳方法。您只需设置一个 servlet 过滤器,以便在接收请求时将所需的对象“注入”到线程中,并在返回响应时将其“取消注入”。
这是一个聪明人的 DI,没有所有丑陋的 XML,没有 Spring Jars 的 MB(更不用说它的学习曲线),也没有所有神秘的重复 @annotation 废话,并且因为它不会单独注入许多带有依赖项的对象实例,所以它可能是速度快得多并且使用的内存更少。
它工作得很好,我们开源了我们的 exPOJO 过滤器,它可以使用 ThreadLocal 注入 Hibernate 会话或 JDO PersistenceManager:
http://www.expojo.com世博网
I have found using ThreadLocal is an excellent way to implement Dependency Injection in a HTTP request/response environment (i.e. any webapp). You just set up a servlet filter to 'inject' the object you need into the thread on receiving the request and 'uninject' it on returning the response.
It's a smart man's DI without all the XML ugliness, without the MB of Spring Jars (not to mention its learning curve) and without all the cryptic repetitive @annotation nonsense and because it doesn't individually inject many object instances with the dependencies it's probably a heck of a lot faster and uses less memory.
It worked so well we opened sourced our exPOJO Filter that can inject a Hibernate session or a JDO PersistenceManager using ThreadLocal:
http://www.expojo.com