如何知道什么是不是线程安全的ruby?

编程入门 行业动态 更新时间:2024-10-26 22:27:53
本文介绍了如何知道什么是不是线程安全的ruby?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

从Rails 4开始,在默认情况下,所有内容都必须在线程环境中运行。这意味着我们写的所有代码 AND _ ALL _我们使用的gem需要 threadsafe

starting from Rails 4, everything would have to run in threaded environment by default. What this means is all of the code we write AND _ALL_ the gems we use are required to be threadsafe

所以,我有几个问题:

  • 什么是NOT thread - 安全在ruby / rails? Vs 什么是ruby / rails中的线程安全?
  • 是否有 -versa?
  • 是有线程安全的代码的常见模式列表 @result || = some_method ?
  • 是否为ruby lang核心中的数据结构,例如 Hash 等线程安全?
  • 有 GVL / GIL 这意味着除了 IO ,一次只能运行一个ruby线程,线程安全更改是否影响我们?
  • what is NOT thread-safe in ruby/rails? Vs What is thread-safe in ruby/rails?
  • Is there a list of gems that is known to be threadsafe or vice-versa?
  • is there List of common patterns of code which are NOT threadsafe example @result ||= some_method?
  • Are the data structures in ruby lang core such as Hash etc threadsafe?
  • On MRI, where there a GVL/GIL which means only 1 ruby thread can run at a time except for IO, does the threadsafe change effect us?
  • 推荐答案

    没有核心数据结构是线程安全的。我知道的唯一一个Ruby是标准库中的队列实现( require'thread'; q = Queue.new )。

    None of the core data structures are thread safe. The only one I know of that ships with Ruby is the queue implementation in the standard library (require 'thread'; q = Queue.new).

    MRI的GIL不会挽救我们的线程安全问题。它只能确保两个线程不能同时运行Ruby代码,即在同一时间在两个不同的CPU上。线程仍然可以在代码中的任何点暂停和恢复。如果你写的代码如 @n = 0; 3.times {Thread.start {100.times {@n + = 1}}} 例如从多个线程改变共享变量,共享变量的值之后不是确定性的。 GIL或多或少是单核系统的模拟,它不会改变编写正确并发程序的根本问题。

    MRI's GIL does not save us from thread safety issues. It only makes sure that two threads cannot run Ruby code at the same time, i.e. on two different CPUs at the exact same time. Threads can still be paused and resumed at any point in your code. If you write code like @n = 0; 3.times { Thread.start { 100.times { @n += 1 } } } e.g. mutating a shared variable from multiple threads, the value of the shared variable afterwards is not deterministic. The GIL is more or less a simulation of a single core system, it does not change the fundamental issues of writing correct concurrent programs.

    即使MRI像Node.js这样的单线程,你仍然需要考虑并发。具有增量变量的示例将正常工作,但是您仍然可以获得竞态条件,其中事件以非确定性顺序发生,一个回调破坏另一个的结果。单线程异步系统更容易理解,但他们不是没有并发问题。只想一个有多个用户的应用程序:如果两个用户或多或少在同一时间点击编辑堆栈溢出帖子,花一些时间编辑帖子,然后点击保存,其更改将被第三个用户以后看到他们阅读同一篇文章?

    Even if MRI had been single-threaded like Node.js you would still have to think about concurrency. The example with the incremented variable would work fine, but you can still get race conditions where things happen in non-deterministic order and one callback clobbers the result of another. Single threaded asynchronous systems are easier to reason about, but they are not free from concurrency issues. Just think of an application with multiple users: if two users hit edit on a Stack Overflow post at more or less the same time, spend some time editing the post and then hit save, whose changes will be seen by a third user later when they read that same post?

    在Ruby中,与大多数其他并发运行时一样,任何多个操作都不是线程安全的。 @n + = 1 不是线程安全的,因为它是多个操作。 @n = 1 是线程安全的,因为它是一个操作(它是很多操作下,我可能会陷入麻烦,如果我试图描述为什么是线程安全,但最终你不会得到不一致的结果从分配)。 @n || = 1 ,不是,也没有其他的简写操作+赋值。一个错误,我做了很多次写返回除非@started; @started = true ,这根本不是线程安全的。

    In Ruby, as in most other concurrent runtimes, anything that is more than one operation is not thread safe. @n += 1 is not thread safe, because it is multiple operations. @n = 1 is thread safe because it is one operation (it's lots of operations under the hood, and I would probably get into trouble if I tried to describe why it's "thread safe" in detail, but in the end you will not get inconsistent results from assignments). @n ||= 1, is not and no other shorthand operation + assignment is either. One mistake I've made many times is writing return unless @started; @started = true, which is not thread safe at all.

    我不知道任何权威的线程安全列表, Ruby的线程安全语句,但有一个简单的经验法则:如果表达式只有一个(副作用自由)操作,它可能是线程安全的。例如: a + b 是确定, a = b 也可以,并且 a .foo(b)是确定,如果方法 foo 是无副作用的 Ruby是一个方法调用,在许多情况下甚至分配,这也适用于其他示例)。在这种情况下的副作用意味着改变状态的东西。 def foo(x); @x = x;

    I don't know of any authoritative list of thread safe and non-thread safe statements for Ruby, but there is a simple rule of thumb: if an expression only does one (side-effect free) operation it is probably thread safe. For example: a + b is ok, a = b is also ok, and a.foo(b) is ok, if the method foo is side-effect free (since just about anything in Ruby is a method call, even assignment in many cases, this goes for the other examples too). Side-effects in this context means things that change state. def foo(x); @x = x; end is not side-effect free.

    在Ruby中编写线程安全代码最困难的事情之一是所有核心数据结构(包括数组,散列和字符串)都是可变的。这是很容易意外泄漏一块你的状态,当那块是可变的事情可以真的搞砸了。考虑下面的代码:

    One of the hardest things about writing thread safe code in Ruby is that all core data structures, including array, hash and string, are mutable. It's very easy to accidentally leak a piece of your state, and when that piece is mutable things can get really screwed up. Consider the following code:

    class Thing attr_reader :stuff def initialize(initial_stuff) @stuff = initial_stuff @state_lock = Mutex.new end def add(item) @state_lock.synchronize do @stuff << item end end end

    可以在线程之间共享,他们可以安全地添加东西到它,但有一个并发错误(它不是唯一的):对象的内部状态泄漏通过东西访问器。除了从封装的角度来看是有问题的,它还打开了一个并发蠕虫。也许有人拿这个数组,并把它传递到别的地方,该代码反过来认为它现在拥有该数组,并可以做任何它想要的东西。

    A instance of this class can be shared between threads and they can safely add things to it, but there's a concurrency bug (it's not the only one): the internal state of the object leaks through the stuff accessor. Besides being problematic from the encapsulation perspective, it also opens up a can of concurrency worms. Maybe someone takes that array and passes it on to somewhere else, and that code in turn thinks it now owns that array and can do whatever it wants with it.

    另一个经典Ruby示例是:

    Another classic Ruby example is this:

    STANDARD_OPTIONS = {:color => 'red', :count => 10} def find_stuff @some_service.load_things('stuff', STANDARD_OPTIONS) end

    find_stuff 在第一次使用时工作正常,但第二次返回其他值。为什么? load_things 方法恰好认为它拥有传递给它的选项哈希,并且 color = options.delete(:color)。现在 STANDARD_OPTIONS 常量不再具有相同的值。常量在它们所引用的内容中仅是常量,它们不保证它们所引用的数据结构的恒定性。

    find_stuff works fine the first time it's used, but returns something else the second time. Why? The load_things method happens to think it owns the options hash passed to it, and does color = options.delete(:color). Now the STANDARD_OPTIONS constant doesn't have the same value anymore. Constants are only constant in what they reference, they do not guarantee the constancy of the data structures they refer to. Just think what would happen if this code was run concurrently.

    如果避免共享可变状态(例如,由多个线程访问的对象中的实例变量,散列和数组等数据结构)访问由多个线程)线程安全不是那么难。尝试最小化同时访问的应用程序的部分,并集中精力在那里。 IIRC在Rails应用程序中,为每个请求创建一个新的控制器对象,因此它只能被单个线程使用,并且对于从该控制器创建的任何模型对象也是如此。但是,Rails还鼓励使用全局变量( User.find(...)使用全局变量 User ,你可能认为它只是一个类,它是一个类,但它也是全局变量的命名空间),其中一些是安全的,因为它们是只读的,但有时你保存在这些全局变量的东西,因为它方便。在使用任何可以全局访问的任何东西时非常小心。

    If you avoid shared mutable state (e.g. instance variables in objects accessed by multiple threads, data structures like hashes and arrays accessed by multiple threads) thread safety isn't so hard. Try to minimize the parts of your application that are accessed concurrently, and focus your efforts there. IIRC, in a Rails application, a new controller object is created for every request, so it is only going to get used by a single thread, and the same goes for any model objects you create from that controller. However, Rails also encourages the use of global variables (User.find(...) uses the global variable User, you may think of it as only a class, and it is a class, but it is also a namespace for global variables), some of these are safe because they are read only, but sometimes you save things in these global variables because it is convenient. Be very careful when you use anything that is globally accessible.

    现在可以在线程环境中运行Rails,所以不需要Rails专家仍然远远地说,你不必担心线程安全,当谈到Rails本身。您仍然可以通过执行上面提到的一些操作来创建不是线程安全的Rails应用程序。当它来的其他宝石假设他们不是线程安全,除非他们说,他们是,如果他们说,他们假设他们不是,看看他们的代码(但只是因为你看到他们去的东西像 @n || = 1 并不意味着他们不是线程安全的,这是一个完全合法的事情,在正确的上下文中 - 你应该寻找可变状态全局变量,它如何处理传递给它的方法的可变对象,特别是如何处理选项哈希)。

    It's been possible to run Rails in threaded environments for quite a while now, so without being a Rails expert I would still go so far as to say that you don't have to worry about thread safety when it comes to Rails itself. You can still create Rails applications that aren't thread safe by doing some of the things I mention above. When it comes other gems assume that they are not thread safe unless they say that they are, and if they say that they are assume that they are not, and look through their code (but just because you see that they go things like @n ||= 1 does not mean that they are not thread safe, that's a perfectly legitimate thing to do in the right context -- you should instead look for things like mutable state in global variables, how it handles mutable objects passed to its methods, and especially how it handles options hashes).

    最后,线程不安全是一个传递属性。任何使用不是线程安全的东西本身不是线程安全的。

    Finally, being thread unsafe is a transitive property. Anything that uses something that is not thread safe is itself not thread safe.

    更多推荐

    如何知道什么是不是线程安全的ruby?

    本文发布于:2023-08-04 23:06:44,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1300389.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:线程   ruby

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!