Thiết kế nhà máy bộ nhớ đệm


9

Tôi có một nhà máy class XFactorytạo ra các đối tượng class X. Các trường hợp Xrất lớn, vì vậy mục đích chính của nhà máy là lưu trữ chúng, càng rõ ràng với mã máy khách càng tốt. Đối tượng class Xlà bất biến, vì vậy đoạn mã sau có vẻ hợp lý:

# module xfactory.py
import x
class XFactory:
  _registry = {}

  def get_x(self, arg1, arg2, use_cache = True):
    if use_cache:
      hash_id = hash((arg1, arg2))
      if hash_id in _registry:
        return _registry[hash_id]
    obj = x.X(arg1, arg2)
    _registry[hash_id] = obj
    return obj

# module x.py
class X:
  # ...

Đó có phải là một mô hình tốt? (Tôi biết đó không phải là Mô hình Nhà máy thực tế.) Có điều gì tôi nên thay đổi không?

Bây giờ, tôi thấy rằng đôi khi tôi muốn lưu trữ Xcác đối tượng vào đĩa. Tôi sẽ sử dụng picklecho mục đích đó và lưu trữ dưới dạng các giá trị trong _registrytên tệp của các đối tượng được chọn thay vì tham chiếu đến các đối tượng. Tất nhiên, _registrybản thân nó sẽ phải được lưu trữ liên tục (có thể trong một tệp dưa của chính nó, trong tệp văn bản, trong cơ sở dữ liệu hoặc đơn giản bằng cách cung cấp cho các tệp dưa chua tên tệp có chứa hash_id).

Ngoại trừ bây giờ tính hợp lệ của đối tượng được lưu trữ không chỉ phụ thuộc vào các tham số được truyền đến get_x()mà còn phụ thuộc vào phiên bản mã đã tạo ra các đối tượng này.

Nói một cách chính xác, ngay cả một đối tượng được lưu trong bộ nhớ cũng có thể trở nên không hợp lệ nếu ai đó sửa đổi x.pyhoặc bất kỳ phụ thuộc nào của nó và tải lại nó trong khi chương trình đang chạy. Cho đến nay tôi đã bỏ qua mối nguy hiểm này vì nó dường như không thể cho ứng dụng của tôi. Nhưng tôi chắc chắn không thể bỏ qua nó khi các đối tượng của tôi được lưu trữ vào bộ nhớ lưu trữ liên tục.

Tôi có thể làm gì? Tôi cho rằng tôi có thể làm cho hash_idmạnh mẽ hơn bằng cách tính băm của một tuple có chứa các đối số arg1arg2, cũng như tên tệp và ngày sửa đổi cuối cùng cho x.pyvà mọi mô-đun và tệp dữ liệu mà nó (đệ quy) phụ thuộc vào. Để giúp xóa các tệp bộ nhớ cache sẽ không bao giờ hữu ích nữa, tôi thêm vào phần _registryđại diện chưa được chỉnh sửa của các ngày đã sửa đổi cho mỗi bản ghi.

Nhưng ngay cả giải pháp này không an toàn 100% vì về mặt lý thuyết, ai đó có thể tải mô-đun một cách linh hoạt và tôi sẽ không biết về nó từ việc phân tích tĩnh mã nguồn. Nếu tôi đi ra ngoài và giả sử mọi tệp trong dự án là một phụ thuộc, cơ chế vẫn sẽ bị hỏng nếu một số mô-đun lấy dữ liệu từ một trang web bên ngoài, v.v.).

Ngoài ra, tần suất thay đổi x.pyvà phụ thuộc của nó khá cao, dẫn đến mất hiệu lực bộ đệm nặng.

Vì vậy, tôi cho rằng tôi cũng có thể từ bỏ một số an toàn và chỉ làm mất hiệu lực bộ đệm chỉ khi có sự không phù hợp rõ ràng. Điều này có nghĩa là class Xsẽ có một định danh xác thực bộ đệm cấp độ lớp nên được thay đổi bất cứ khi nào nhà phát triển tin rằng một thay đổi xảy ra sẽ làm mất hiệu lực bộ đệm. (Với nhiều nhà phát triển, một định huỷ bỏ hiệu riêng biệt là cần thiết cho mỗi người.) Định danh này được băm cùng với arg1arg2và trở thành một phần trong những chìa khóa băm lưu trữ trong _registry.

Vì các nhà phát triển có thể quên cập nhật mã nhận dạng xác thực hoặc không nhận ra rằng họ đã vô hiệu hóa bộ đệm hiện có, nên có thể tốt hơn để thêm một cơ chế xác thực khác: class Xcó thể có một phương thức trả về tất cả các "đặc điểm" đã biết X. Chẳng hạn, nếu Xlà một bảng, tôi có thể thêm tên của tất cả các cột. Tính toán băm sẽ bao gồm các đặc điểm là tốt.

Tôi có thể viết mã này, nhưng tôi sợ rằng tôi đang thiếu một cái gì đó quan trọng; và tôi cũng tự hỏi liệu có lẽ đã có một khung hoặc gói có thể thực hiện tất cả những thứ này chưa. Lý tưởng nhất, tôi muốn kết hợp bộ nhớ đệm trong bộ nhớ và dựa trên đĩa.

BIÊN TẬP:

Dường như nhu cầu của tôi có thể được phục vụ tốt bởi một mô hình hồ bơi. Tuy nhiên, về điều tra thêm, nó không phải là trường hợp. Tôi nghĩ tôi sẽ liệt kê sự khác biệt:

  1. Một đối tượng có thể được sử dụng bởi nhiều khách hàng?

    • Bi-a: Không, mỗi đối tượng cần được kiểm tra và sau đó kiểm tra khi không còn cần thiết. Cơ chế chính xác có thể phức tạp.
    • XFactory: Có. Đối tượng là bất biến, và có thể được sử dụng bởi vô số khách hàng cùng một lúc. Không bao giờ cần phải tạo một bản sao thứ hai của cùng một đối tượng.
  2. Có kích thước hồ bơi cần phải được kiểm soát?

    • Bể bơi: Thường, có. Nếu vậy, chiến lược để làm như vậy có thể khá phức tạp.
    • XFactory: Không. Một đối tượng phải được cung cấp theo yêu cầu cho khách hàng và nếu một đối tượng hiện tại không phù hợp, một đối tượng mới cần được tạo.
  3. Có phải tất cả các đối tượng tự do thay thế?

    • Bi-a: Có, các đối tượng thường có thể thay thế tự do (hoặc nếu không, việc kiểm tra đối tượng khách hàng cần là không quan trọng).
    • XFactory: Hoàn toàn không, và rất khó để tìm hiểu xem một đối tượng nhất định có thể phục vụ một yêu cầu khách hàng nhất định hay không. Nó phụ thuộc vào việc một đối tượng hiện có có được tạo ra với (a) cùng các đối số và (b) cùng một phiên bản của mã nguồn hay không. Phần (b) không thể được xác minh bởi XFactory, vì vậy nó yêu cầu khách hàng giúp đỡ. Khách hàng hoàn thành trách nhiệm này theo hai cách. Đầu tiên, khách hàng có thể tăng bất kỳ bộ đếm phiên bản nội bộ nào được chỉ định (một cho mỗi nhà phát triển). Điều này không thể xảy ra trong thời gian chạy, chỉ nhà phát triển mới có thể thay đổi các bộ đếm này khi anh ta tin rằng việc thay đổi mã nguồn làm cho các đối tượng hiện tại không thể sử dụng được. Thứ hai, một khách hàng sẽ trả về một số bất biến về các đối tượng mà nó cần và XFactory sẽ xác minh rằng các bất biến này không bị vi phạm trước khi phục vụ đối tượng cho khách hàng. Nếu bất kỳ kiểm tra nào thất bại,
  4. Liệu tác động hiệu suất cần phân tích cẩn thận?

    • Nhóm: Có, trong một số trường hợp, một nhóm thực sự làm tổn hại đến hiệu suất nếu tổng chi phí quản lý đối tượng lớn hơn tổng chi phí tạo / hủy đối tượng.
    • XFactory: Không. Chi phí tính toán của các đối tượng trong câu hỏi được biết là rất cao và việc tải chúng từ bộ nhớ hoặc từ đĩa chắc chắn là vượt trội hơn so với việc tính toán lại chúng từ đầu.
  5. Khi nào đồ vật bị phá hủy?

    • Bể bơi: Khi bể bơi ngừng hoạt động. Có lẽ nó cũng có thể phá hủy các đối tượng nếu được yêu cầu (một phần) giải phóng tài nguyên hoặc nếu một số đối tượng nhất định không được sử dụng trong một thời gian.
    • XFactory: Bất cứ khi nào một đối tượng được tạo ra với phiên bản của mã nguồn không còn hiện hành, bằng chứng là vi phạm bất biến hoặc không khớp. Quá trình định vị và tiêu diệt những vật thể như vậy vào đúng thời điểm khá phức tạp. Ngoài ra, việc vô hiệu hóa theo thời gian của tất cả các đối tượng có thể được thực hiện để giảm rủi ro tích lũy khi sử dụng các đối tượng không hợp lệ. Vì XFactory không bao giờ chắc chắn rằng nó là chủ sở hữu duy nhất của một đối tượng, nên tính hợp lệ đó đạt được tốt nhất bởi một phiên bản bổ sung đối với các đối tượng khách hàng, được tăng cường theo chương trình trên cơ sở định kỳ, thay vì nhà phát triển.
  6. Những cân nhắc đặc biệt nào tồn tại cho môi trường đa luồng?

    • Bi-a: Phải tránh va chạm trong việc kiểm tra / kiểm tra đối tượng (không muốn kiểm tra một đối tượng cho hai khách hàng)
    • XFactory: Phải tránh xung đột khi tạo đối tượng (không muốn tạo hai đối tượng dựa trên hai yêu cầu giống nhau)
  7. Những gì cần phải được thực hiện nếu khách hàng không phát hành một đối tượng?

    • Bi-a: Nó có thể muốn làm cho đối tượng có sẵn cho người khác sau khi chờ đợi một thời gian.
    • XFactory: Không áp dụng. Khách hàng không thông báo cho XFactory về thời điểm họ thực hiện với đối tượng.
  8. Các đối tượng cần phải được sửa đổi?

    • Bi-a: Có thể phải được đặt lại về trạng thái mặc định trước khi được sử dụng lại.
    • XFactory: Không, các đối tượng là bất biến.
  9. Có bất kỳ cân nhắc đặc biệt liên quan đến sự kiên trì của các đối tượng?

    • Bể bơi: Điển hình là không. Một pool là về việc tiết kiệm chi phí tạo đối tượng, vì vậy tất cả các đối tượng được lưu trong bộ nhớ (đọc từ đĩa sẽ đánh bại mục đích).
    • XFactory: Có, XFactory là về việc tiết kiệm chi phí thực hiện các phép tính phức tạp, vì vậy việc lưu trữ các đối tượng được tính toán trước trên đĩa có ý nghĩa. Kết quả là XFactory cần phải giải quyết các vấn đề điển hình của việc lưu trữ liên tục; ví dụ: khi khởi tạo, nó cần kết nối với bộ lưu trữ liên tục, lấy từ siêu dữ liệu về các đối tượng hiện có sẵn ở đó và sẵn sàng tải chúng vào bộ nhớ nếu được yêu cầu. Và đối tượng có thể ở một trong ba trạng thái: Không tồn tại, mà tồn tại trên đĩa, còn tồn tại trên bộ nhớ. Trong khi XFactory đang chạy, trạng thái chỉ có thể thay đổi theo một hướng (bên phải trong chuỗi này).

Tóm lại, độ phức tạp của nhóm nằm trong các mục 1, 2, 4, 6 và có thể là 5, 7, 8. Độ phức tạp XFactory nằm ở các mục 3, 6, 9. Sự chồng chéo duy nhất là mục 6 và thực sự không phải là cốt lõi chức năng của pool hoặc XFactory, nhưng thay vào đó là một ràng buộc đối với thiết kế phổ biến đối với bất kỳ mẫu nào cần hoạt động trong môi trường đa luồng.


1
Đây chắc chắn không phải là một nhà máy hoặc thậm chí đóng cửa thực sự. Nhà máy là về việc xây dựng không xác định cho phép tạo ra một loại bê tông từ một đặc điểm kỹ thuật trừu tượng. Đây là một hồ bơi. Nó không tệ lắm, nhưng bây giờ bạn biết đó là nhóm đối tượng mà bạn đang tìm kiếm, tôi khuyên bạn nên đọc các thực tiễn tốt với các nhóm và tìm kiếm sự cẩn thận mà mọi người đã học để tránh và cách tránh hiện thực hóa các vấn đề họ gặp phải ' d chịu. Bắt đầu tại đây: vi.wikipedia.org/wiki/Object_pool_potype
Jimmy Hoffa

1
Cảm ơn. Tôi thấy cách đọc này rất hữu ích, nhưng những gì tôi cần không hoàn toàn là mô hình nhóm. Tôi chỉnh sửa câu hỏi của tôi để cho thấy tại sao.
tối đa

Câu trả lời:


4

Mối quan tâm của bạn rất hợp lệ và chúng cho tôi biết giải pháp bộ nhớ đệm dễ dàng ban đầu của bạn cuối cùng trở thành một phần của kiến ​​trúc của bạn, điều này tự nhiên mang đến một mức độ mới của các vấn đề như bạn mô tả về chính mình.

Một giải pháp kiến ​​trúc tốt cho bộ nhớ đệm là sử dụng các chú thích kết hợp với IoC để giải quyết một số vấn đề bạn mô tả. Ví dụ:

  • Cho phép bạn kiểm soát tốt hơn vòng đời của các đối tượng được lưu trong bộ nhớ cache của bạn
  • Cho phép bạn thay thế hành vi bộ đệm một cách dễ dàng bằng cách thay đổi các chú thích (thay vì thay đổi việc thực hiện)
  • Cho phép bạn dễ dàng định cấu hình bộ đệm nhiều lớp nơi bạn có thể lưu trữ trong bộ nhớ, sau đó bộ đệm đĩa chẳng hạn
  • Cho phép bạn xác định khóa (hàm băm) cho mỗi phương thức trong chính chú thích

Trong các dự án của tôi (Java hoặc C #), tôi sử dụng các chú thích bộ đệm mùa xuân. Bạn có thể tìm thấy một mô tả ngắn gọn ở đây .

IoC là một khái niệm quan trọng trong giải pháp này vì nó cho phép bạn định cấu hình hệ thống bộ nhớ đệm của mình theo bất cứ cách nào bạn muốn.

Để thực hiện một giải pháp tương tự trong Python, bạn phải tìm cách sử dụng các chú thích và tìm kiếm một bộ chứa IoC cho phép bạn xây dựng các proxy. Đó là cách các chú thích hoạt động để chặn tất cả các cuộc gọi phương thức và cung cấp cho bạn giải pháp cụ thể này để lưu vào bộ đệm.


Cảm ơn, tôi chưa bao giờ nghe nói về IoC cho đến bây giờ, và nó dường như vừa thú vị vừa có liên quan. Dường như có một số ví dụ hay về IoC trong Python.
tối đa

@max IoC có lẽ không phải là một vấn đề lớn. Nhưng để có một khung bộ đệm tốt, bạn phải tìm cách chặn các cuộc gọi phương thức (thường là với các proxy tự động) và sau đó sử dụng chú thích để thực hiện hành vi bộ đệm mà bạn muốn. Chúc may mắn!
Alex

1

Theo cách tôi thấy thì bộ đệm vẫn ổn - X thì không.

IMHO khử tuần tự hóa các trường hợp đơn lẻ không phải là vấn đề của bộ đệm. Đây là một nhiệm vụ cho lớp học theo. Vấn đề chính ở đây là lớp học này đang thay đổi thường xuyên. Tôi đề nghị tách riêng mối quan tâm của các trường hợp bộ đệm và mối quan tâm của việc khử tuần tự hóa đối tượng. Cái sau phải được cải thiện để X cũng có thể khử tuần tự các định dạng cũ hơn. Điều này có thể rất khó khăn và tốn kém. Nếu nó quá đắt, bạn phải tự hỏi mình có thực sự cần tải các phiên bản cũ miễn là X thay đổi thường xuyên không?

BTW một định danh phiên bản dường như là bắt buộc. Không có kiến ​​thức sâu hơn về cấu trúc của XI chỉ có thể đưa ra một số dự đoán, nhưng cấu trúc của X dường như là mô-đun logic (ví dụ: bạn đã nói về các đặc điểm). Nếu vậy, có lẽ nó sẽ giúp làm cho cấu trúc này rõ ràng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.