Ruby/Rails 线程安全
我时不时地使用 Ruby,但我还没有用它做过任何大型或多线程的事情。 我听说 MRI 仅支持绿色线程,而 JRuby 通过 JVM 支持本机线程。 然而,我偶然发现博客和讨论组上的评论说“Rails 不是线程安全的”或者 Ruby 本身不是线程安全的。 例如有人评论说 require 语句有问题。 这听起来有点基础。
我见过很多不能正确处理并发的 Java 应用程序,而且我时常会做噩梦 :-) 但至少你可以用 Java 编写线程安全的应用程序,如果你< em>真的知道自己在做什么(这并不容易)。
这一切听起来相当令人震惊,有人可以详细说明一下 - 问题到底是什么以及如果是这种情况,Rails 是如何工作的? 我可以编写在没有竞争条件和死锁的情况下正常工作的多线程 Ruby 代码吗? 它是否可以在 JRuby 和 MRI 之间移植,或者我是否必须侵入 JVM 特定代码才能正确利用 JVM 本机线程?
编辑:
我应该问两个问题,因为人们似乎只回答 Rails 线程问题(这本身就很好)和绿色线程与本机线程。 我对有关线程安全的核心 Ruby 问题的担忧尚未真正得到解决。 require 中似乎至少存在一个(未解决?)问题某些情况。
I have been hacking with Ruby from time to time, but I haven't done anything big or multithreaded with it. I have heard that MRI only supports green threads and JRuby supports native threads via JVM. However, I stumble upon comments on blogs and discussion groups which say that "Rails is not thread-safe" or that Ruby itself is not thread safe. For example someone commented that there is a problem with the require statement. That sounds a bit fundamental.
I have seen a lot of Java apps which don't handle concurrency properly and I have nightmares about them from time to time :-) But at least you can write thread-safe applications in Java if you really know what you are doing (it's just not easy).
This all sounds quite alarming, can someone elaborate more - what is exactly the problem and how Rails manages to work at all if this is the case? Can I write multithreaded Ruby code which works correctly without race conditions and deadlocks? Is it portable between JRuby and MRI or do I have to hack in JVM specific code to take advantage of the JVM native threads properly?
EDIT:
I should have asked two questions, because people only seem to answer the rails threading stuff (which is nice in itself) and green threading vs. native threading. My concerns on core Ruby issues about thread safety haven't really been addressed. There seems to be at least an (unresolved?) issue with require in certain cases.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先也是最重要的,Ruby 1.9(最新的官方版本)现在使用本机(内核)线程。 Ruby 的早期版本使用绿色线程。 简而言之,在 1.9 之前,线程在大大小小的 Ruby 应用程序中并不常用,因为它们不是特别安全或可靠。
这并不是特别令人担忧,因为在 2.2 版本之前,Rails 并未尝试实现线程安全,因此我们通常通过使用多个进程、数据库记录锁定和消息队列(如 八哥。 这通常是一种相当可靠的扩展 Web 应用程序的方法(至少与不正确的多线程 Java 应用程序一样可靠),并且具有额外的优点,即可以更轻松地横向扩展应用程序到多个处理器和服务器。
我不知道您提到的“require”问题是否已在 1.9 中得到解决,但我冒昧地说,如果您在新线程中动态地需要库,那么您将遇到多个可维护性问题。
如果您想完全避免线程,Ruby 1.9 也支持纤程,它采用无共享方法来实现并发,并且据我所知,通常比线程更容易编写和维护。 此处的性能数据。
First and foremost, Ruby 1.9 (the most recent official release) now uses native (kernel) threads. Previous versions of Ruby used green threads. To answer your question succinctly, prior to 1.9, threads have not commonly been used in Ruby applications large or small precisely because they're not particularly safe or reliable.
This is not particularly alarming because prior to version 2.2 Rails made no attempt to be threadsafe, and so we typically handle asynchronous processing through the use of multiple processes, database record locking, and message queues like Starling. This is generally a pretty reliable way to scale a web application--at least as reliable than incorrectly multithreaded Java applications--and has the added advantage that it becomes easier to scale your application sideways to multiple processors and servers.
I have no idea whether the 'require' issue you've mentioned has been resolved as of 1.9, but I do humbly venture that if you're requiring libraries dynamically in new threads then you have more than one maintainability problem.
If you'd like to avoid threads entirely, Ruby 1.9 also supports fibers, which employ a shared-nothing approach to concurrency and are, from what I gather, generally easier to write and maintain than threads. Performance numbers here.
我强烈建议您观看 Jim Weirich 在 RubyConf 2008 上的演讲(非常有趣且内容丰富:):
https://www.youtube.com/watch?v=fK-N_VxdW7g
这个也不错:
http://rubyconf2008.confreaks.com/summer-of-code-rails-thread-safety.html
I really suggest you to watch Jim Weirich`s speech from RubyConf 2008 (it's very funny and informative:) :
https://www.youtube.com/watch?v=fK-N_VxdW7g
This one is nice too:
http://rubyconf2008.confreaks.com/summer-of-code-rails-thread-safety.html
MRI 的正常解决方案是运行多个 Rails 实例,每个实例独立处理请求。 由于 MRI 无论如何都不是多线程的,因此您无法在其上运行多个 Rails 实例。 这意味着您会受到内存占用,因为每个 Ruby 进程都会加载一次 Rails。
由于 JRuby 支持本机线程,因此您始终可以在单个 JVM 中运行多个 Rails 实例。 但由于 Rails 是线程安全的,您可以将其减少到 1,这意味着更低的内存使用量和更少的 JIT 编译。
Charles Nutter (JRuby) 有一个很好的总结。
The normal solution for MRI is to run multiple Rails instances, each handling requests independently. Since MRI isn't multithreaded anyway, you can't run multiple Rails instances on top of it. This means you take a memory hit since Rails is loaded once per Ruby process.
Since JRuby supports native threads, you could always run several Rails instances in a single JVM. But with Rails being thread-safe, you can cut it down to one, which means lower memory usage and less JIT compilation.
Charles Nutter (JRuby) has a nice summary.
我认为之前的海报很好地涵盖了 Rails 案例,因此我不会费心去讨论这类内容。
编写线程 Ruby 应用程序当然是可能的。 ruby 线程存在的一些问题是它们是“绿色”的,因为它们是由虚拟机管理的。 目前,默认解释器 (MRI) 只有一个真正的系统线程,需要由解释器控制的所有线程共享。
这样做的缺点是,如果您的计算机具有多个处理器或多核,则应用程序中的线程不能在其他核心上运行。 对于运行服务器和高性能应用程序的人来说,这是一个相当大的问题。
至于你的解释器特定代码问题:我不这么认为。 AFAIK 你不需要做任何特殊的事情来处理 JRuby/JVM 线程。
另外:这篇文章结束在 Igvita 上,它很好地了解了 Ruby 中的并发状态。
I think the previous posters covered the Rails cases pretty well, so I won't bother going into that sort of stuff.
It's certainly possible to write threaded Ruby applications. Some of the problems that exist with ruby threads is that they are 'green' in as they are managed by the virtual machine. Currently, the default interpreter (MRI) only has one true system thread that need to be shared by all of the threads that the interpreter has control over.
The downside to this is that if you have a computer with multiple processors or cores you can't have a thread in your application running on some other core. This is a pretty big deal for people running servers and high performance apps.
As for your interpreter-specific-code question: I don't think so. AFAIK you don't have to do anything special to take care of JRuby/JVM threads.
Also: This article over on Igvita that takes a good look at the state of concurrency in Ruby.