2009-03-30 25 views
23

Vào giữa tháng 7 năm 2008, bản ghi nhớ đã được thêm vào lõi Rails. Một minh họa về cách sử dụng là here.Khi nào sử dụng tính năng ghi nhớ trong Ruby on Rails

Tôi không thể tìm thấy bất kỳ ví dụ hay nào về thời điểm phương pháp cần được ghi nhớ và các tác động hiệu quả của từng phương pháp. Ví dụ: This blog post, gợi ý rằng đôi khi, không nên sử dụng tính năng ghi nhớ.

Đối với điều gì đó có khả năng có thể có tác động to lớn về hiệu suất, có vẻ như có ít tài nguyên đi xa hơn việc cung cấp hướng dẫn đơn giản.

Có ai đã xem ghi nhớ được sử dụng trong các dự án của riêng họ không? Yếu tố nào khiến bạn cân nhắc việc ghi nhớ một phương pháp?


Sau khi tự mình thực hiện một số nghiên cứu nữa, tôi thấy rằng việc ghi nhớ được sử dụng một số lần đáng kể trong lõi Rails.

Dưới đây là ví dụ: http://github.com/rails/rails/blob/1182658e767d2db4a46faed35f0b1075c5dd9a88/actionpack/lib/action_view/template.rb.

Cách sử dụng này dường như đi ngược lại những phát hiện của bài đăng trên blog mà việc tìm thấy ghi nhớ có thể ảnh hưởng đến hiệu suất.

Trả lời

33

Tôi nghĩ rằng nhiều nhà phát triển Rails không hiểu đầy đủ về tính năng ghi nhớ và cách hoạt động của tính năng ghi nhớ. Tôi đã nhìn thấy nó áp dụng cho các phương thức trả về các bộ sưu tập được tải xuống lười biếng (như một bộ dữ liệu Sequel), hoặc áp dụng cho các phương thức không có đối số nhưng tính toán một cái gì đó dựa trên các biến mẫu. Trong trường hợp đầu tiên, việc ghi nhớ là không có gì ngoài chi phí, và trong lần thứ hai đó là một nguồn khó chịu và khó khăn để theo dõi lỗi.

tôi sẽ không áp dụng memoization nếu

  • giá trị trả về là chỉ hơi đắt để tính toán. Nó sẽ phải là rất tốn kém và không thể tối ưu hóa được nữa, vì nó đáng để ghi nhớ.
  • giá trị trả lại là hoặc có thể được tải chậm
  • phương thức không phải là hàm thuần túy, tức là nó được đảm bảo trả về chính xác cùng một giá trị cho cùng một đối số - và chỉ sử dụng đối số để thực hiện công việc hoặc các chức năng thuần túy khác. Sử dụng các biến mẫu hoặc các phương thức gọi mà lần lượt sử dụng các biến mẫu có nghĩa là phương thức có thể trả về các kết quả khác nhau cho cùng một đối số.

Cũng có những trường hợp khác mà việc ghi nhớ không phù hợp, chẳng hạn như ghi nhớ và câu trả lời ở trên, nhưng đây là ba điều mà tôi cho là không rõ ràng.

Mục cuối cùng có lẽ là quan trọng nhất: memoization lưu trữ kết quả dựa trên những lập luận để phương pháp này, nếu phương pháp này trông như thế này nó không thể được memoized:

def unmemoizable1(name) 
    "%s was here %s" % name, Time.now.strftime('%Y-%m-%d') 
end 

def unmemoizable2 
    find_by_shoe_size(@size) 
end 

Cả hai có thể, tuy nhiên, được viết lại để tận dụng lợi thế của memoization (mặc dù trong hai trường hợp, những nó nên rõ ràng là không được thực hiện vì lý do khác):

def unmemoizable1(name) 
    memoizable1(name, Time.now.strftime('%Y-%m-%d')) 
end 

def memoizable1(name, time) 
    "#{name} was here #{time}" 
end 
memoize :memoizable1 

def unmemoizable2 
    memoizable2(@size) 
end 

def memoizable2(size) 
    find_by_shoe_size(size) 
end 
memoize :memoizable2 

(giả định rằng find_by_shoe_size không có, hoặc dựa vào, bất kỳ tác dụng phụ)

Bí quyết là trích xuất một hàm thuần túy từ phương pháp và áp dụng ghi nhớ cho thay vào đó.

+0

Khi bạn nói "nghĩa là nó được đảm bảo trả lại chính xác cùng một giá trị cho cùng một đối số", điều đó sẽ áp dụng như thế nào với các truy vấn Rails ActiveRecord? Ví dụ: tôi đã ghi nhớ phương thức tìm nạp tất cả các thành phố được đánh dấu là đang hoạt động trong mô hình Thành phố, ví dụ: '' 'def self.active @active_cities = || ("cities.active = (?)", true) kết thúc '' 'Khi thành phố mới được thêm vào cơ sở dữ liệu một cách thường xuyên bởi quản trị viên khi ứng dụng đang hoạt động, tôi có cần phải khởi động lại máy chủ để ghi đè biến mẫu được ghi nhớ này hay không ? Hay một biến mẫu ghi nhớ bị hủy và tái tạo sau mỗi yêu cầu? – Kelseydh

+1

Để trả lời ở trên: Tôi nhận ra rằng * ghi nhớ chỉ tồn tại một biến mẫu trong vòng đời của ** một yêu cầu. *** Đây là điều làm tôi bối rối. Đối với người mới bắt đầu, tôi khuyên bạn nên thêm điểm quan trọng này vào định nghĩa của bạn. – Kelseydh

10

Khi phương thức tìm nạp dữ liệu từ nhiều bảng và thực hiện một số phép tính trước khi trả về đối tượng kết quả và phương thức này nhiều lần trong yêu cầu, việc ghi nhớ có thể có ý nghĩa.

Hãy nhớ rằng bộ đệm truy vấn cũng hoạt động, vì vậy chỉ ghi nhớ các phương thức thực hiện tính toán trong Ruby, chứ không phải tìm nạp cơ sở dữ liệu thuần túy.

+1

Việc xây dựng các đối tượng ActiveRecord có được tính là tính toán không? Như tôi đã hiểu, bộ nhớ cache truy vấn chỉ lưu trữ bộ kết quả mysql chứ không phải các đối tượng được tạo (nơi quá trình tạo thường mất nhiều thời gian hơn bản thân truy vấn). – Gdeglin

+1

Theo như tôi biết, bộ nhớ cache truy vấn lưu trữ các đối tượng ActiveRecord thực tế. –

2

Có lẽ kinh nghiệm của tôi là một ví dụ hay khi KHÔNG sử dụng ghi nhớ. Trong mô hình Đơn đặt hàng của tôi, tôi đã ghi nhớ cả hai kết quả tính toán đơn giản, ví dụ: Số thứ tự phụ, Số đơn đặt hàng; cũng như các đối tượng mô hình, ví dụ: Đơn hàng # most_recent_credit_card_used. Trong phần sau, khi ghi nhớ một phương thức trả về một đối tượng CreditCard, tôi sẽ nhận được các lỗi 'băm cố định' khi cố cập nhật các thuộc tính trên đối tượng đã ghi nhớ. Đơn hàng # most_recent_credit_card_used.frozen? trả về đúng khi phương pháp đã được ghi nhớ, tất nhiên, không phải là những gì tôi dự định.

Việc mang đi của tôi rất đơn giản: sử dụng ghi nhớ cho các hoạt động tốn kém trả về các loại dữ liệu đơn giản (số nguyên, nổi, v.v.) nhưng Không sử dụng ghi nhớ khi trả về các đối tượng phức tạp như mô hình ActiveRecord. nếu bạn dự định cập nhật các đối tượng đó trong bộ nhớ.

Các vấn đề liên quan