2012-12-04 150 views
5

我這樣做(在我看來):紅寶石。每個效率

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

如果用戶有10個職位,這會是做一個數據庫調用十倍?如果這些循環是這樣(非常少)?:

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

Here的是,我做了測試紅寶石文件的糊紙盒。 編輯修改了粘貼文件夾。

這讓我想起的代碼在Java中

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

應(除非修改該數組)

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

我缺少的東西?我看到一些軌道示例,其中人們通過對象的某個has_many字段進行循環。這對我來說很重要,因爲我試圖優化我的應用程序的性能。

回答

10

如果用戶有10個帖子,這在技術上會做數據庫調用10次?

沒有。

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

此處的代碼將運行2個查詢。第一個將通過它的id找到一個用戶,返回一行。第二個將運行一個查詢,詢問具有與myUser匹配的用戶標識的所有帖子。然後each將使用該結果迭代。


如果你看在日誌中的發展模式下,它會告訴你它的運行查詢,你應該會看到一個查詢返回所有那些帖子。

Rails使用關聯代理對象來保存您的查詢,當您需要記錄時執行查詢,然後緩存結果。這是一個非常有用的代碼,大部分它爲你處理這樣的事情。

這是Rails的一個特性,不是紅寶石。


在ruby級別,each只是作用於集合。

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

get_letters.each do |item| 
    puts item 
end 

這應該打印出來。

executing "query" 
a 
b 
c 

get_letters方法執行,它會返回一個數組,一個數組已滿的數據就是我們所說的each方法,這樣我們就可以處理每個項目。獲取集合並遍歷它是2個完全獨立的步驟。


從你的引擎收錄:

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

呀會,但不是因爲陣列被過度過「牽強」。

這相當於像這樣的javascript,這更好地說明了這一點。

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

原來的陣列,在循環檢查的每個迭代,看看它是否沒有完成。但是因爲陣列每次獲得一個項目的時間會增加一個,所以i < myArr.length將始終爲true,因爲它們在每次迭代時都會增加1。出於同樣的原因,您的紅寶石與您的each循環相同。

它永遠運行,不是因爲你不停地運行一些代碼來重新生成數組。它永遠運行,因爲你是人爲地改變結果數組。

+0

謝謝,但問題。在我的粘貼箱作爲最後一個例子,循環永遠運行......我不明白爲什麼會這樣,如果結果會被「緩存」後,Ruby會修改緩存嗎?如果我在.each帖子循環中添加帖子會發生什麼? – K2xL

+0

@ K2xL請參閱我的編輯,它在基本ruby(非rails)圖層上解釋了更多內容。但是,你的循環,正如張貼,絕對不_永遠不會「永遠運行」。 3秒後,完成。 –

+0

看到我的編輯(我無意中發佈了錯誤的pastebin url) – K2xL