简体   繁体   English

Ruby。每个效率

[英]Ruby .each efficiency

I do (in my view): 我(在我看来):

# myUser is a User in ActiveRecord with :has_many :posts
myUser.posts.each do |post|
end

If the user had ten posts, would this be doing a database call ten times? 如果用户有十个帖子,这会是十次进行数据库调用吗? Should these loops be like (less pretty)?: 这些循环应该是(不太漂亮)吗?:

myPosts = myUser.posts
myPosts.each do |post|
end

Here is a paste bin of a ruby file that I did to test. 是我测试的ruby文件的粘贴框。 EDIT Modified the paste bin. 编辑修改了粘贴箱。

This reminds me of code in Java 这让我想起了Java中的代码

for (int i = 0; i < someExpensiveFunction(); i++)

that should be (unless the array is modified) 应该是(除非数组被修改)

for (int i = 0, len=someExpensiveFunction(); i < len; i++)

Am I missing something? 我错过了什么吗? I see a bunch of rails examples where people loop through some has_many field of an object. 我看到一堆rails示例,其中人们遍历对象的某些has_many字段。 This is important to me as I'm trying to optimize my application's performance. 这对我很重要,因为我正在尝试优化我的应用程序的性能。

If the user had 10 posts, this would technically be doing a database call 10 times? 如果用户有10个帖子,这在技术上会进行10次数据库调用吗?

Nope. 不。

myUser = User.find 123
myUser.posts.each do |post|
  puts post.title
end

This code here will run 2 queries. 这段代码将运行2个查询。 The first will find a user by its id, returning a single row. 第一个将通过其id找到用户,返回单行。 The second will run a query asking for all posts which have a user id that matches myUser . 第二个将运行一个查询,询问所有具有与myUser匹配的用户ID的帖子。 Then the each will use the result of that to iterate through. 然后each将使用其结果进行迭代。


If you watch the log in development mode it tells you the queries it's running, and you should see a single query returning all those posts. 如果您观察登录开发模式,它会告诉您正在运行的查询,您应该看到一个查询返回所有这些帖子。

Rails uses an association proxy object to hold your query, execute the query when you need records, and then caches the result . Rails使用关联代理对象来保存查询,在需要记录时执行查询,然后缓存结果 It's a very helpful bit of code and, for the most part, it handles things like this for you. 这是一个非常有用的代码,在大多数情况下,它会为你处理这样的事情。

This is a feature of Rails , not ruby. 这是Rails的一个特性,而不是ruby。


At the ruby level, each simply acts on collections. 在红宝石级别, each只是简单地作用于收藏。

def get_letters
  puts 'executing "query"'
  sleep(3)
  ["a","b","c"]
end

get_letters.each do |item|
  puts item
end

This should print out. 这应该打印出来。

executing "query"
a
b
c

The get_letters method executes, it returns an array, an that array already full of data is what we call the each method on, so we can process each item. get_letters方法执行,它返回一个数组,一个已经充满数据的数组就是我们所说的each方法,所以我们可以处理每个项目。 Fetching the collection and iterating through it are 2 completely separate steps. 获取集合并迭代它是2个完全独立的步骤。


From your pastebin: 从您的pastebin:

# will this run forever?
myArr = ["a","b","c"]
myArr.each do |item|
  myArr.push("x")
end

Yeah it will, But not because the array is being "fetched" over an over. 是的,但不是因为阵列被“取出”了。

This equivalent to javascript like this, which spells it out better. 这相当于像这样的javascript,它更好地说明了它。

myArr = ["a","b","c"];
for (var i = 0; i < myArr.length; i++) {
  myArr.push('x');
}

The original array, on each iteration of the loop checks to see if it's done yet. 原始数组在循环每次迭代中检查它是否已完成。 But because the array gets longer by one every single time we progress by one item, i < myArr.length will always be true because they both increase by one on each iteration. 但是因为每次进行一个项目时数组都会变长一个,所以i < myArr.length将永远为true因为它们在每次迭代时都会增加一。 The same thing is going on in ruby with your each loop, for the same reason. 出于同样的原因,同样的事情在ruby中与你的each循环一起进行。

It runs forever, not because you keep running some code to regenerate the array. 它永远运行,不是因为你继续运行一些代码来重新生成数组。 It runs forever because you are artificially mutating the resulting array. 它会永远运行,因为你人为地改变了生成的数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM