Sự khác biệt về vải giữa Ref, Var, Agent, Atom, với các ví dụ


110

Tôi rất mới với Clojure, các bạn có thể cho tôi lời giải thích với các tình huống trong thế giới thực không. Ý tôi là, nơi sử dụng Ref, Var, Agent, Atom. Tôi đọc sách, nhưng vẫn không thể hiểu được các ví dụ trong thế giới thực.

Câu trả lời:


174

Tôi thực sự khuyên bạn nên sử dụng "Niềm vui của Clojure" hoặc "Lập trình Clojure" để có câu trả lời thực sự cho câu hỏi này, tôi có thể tái tạo một đoạn ngắn về động lực cho mỗi:

bắt đầu bằng cách xem video này về khái niệm Nhận dạng và / hoặc nghiên cứu ở đây .

  • Refs dành cho quyền truy cập Đồng bộ được Phối hợp vào "Nhiều Danh tính".
  • Nguyên tử dành cho quyền truy cập đồng bộ không phối hợp vào một Danh tính duy nhất.
  • Tác nhân dành cho truy cập không đồng bộ Không phối hợp vào một Danh tính duy nhất.
  • Vars dành cho danh tính riêng biệt cục bộ của chuỗi với giá trị mặc định được chia sẻ.

Quyền truy cập phối hợp được sử dụng khi hai Danh tính cần thay đổi cùng nhau, ví dụ cổ điển là chuyển tiền từ tài khoản ngân hàng này sang tài khoản ngân hàng khác, nó cần chuyển hoàn toàn hoặc không.

Quyền truy cập không phối hợp được sử dụng khi chỉ có một Identity cần cập nhật, đây là trường hợp rất phổ biến.

Truy cập đồng bộ được sử dụng khi cuộc gọi dự kiến ​​sẽ đợi cho đến khi tất cả Danh tính đã giải quyết xong trước khi tiếp tục.

Truy cập không đồng bộ là "cháy và quên" và để Danh tính đạt trạng thái mới trong thời gian riêng của nó.


Trong truy cập phối hợp, nếu tôi muốn chỉ thay đổi state-a, nhưng tham khảo khi state-blàm như vậy, tôi vẫn cần một refchính xác? Vì vậy, không phải thay đổi nhiều thứ mà là đề cập đến nhiều thứ trong khi thay đổi bất kỳ thứ nào trong số chúng?
event_jr

2
Có, bạn dường như hiểu đúng rằng trạng thái a và trạng thái b đều phải là refs Nếu bạn muốn giá trị mới trong trạng thái-a dựa trên sự kết hợp nhất quán của các giá trị trong a và b. Bạn cần giá trị mới đó được tính toán trong ngữ cảnh mà trạng thái-a và và trạng thái-b phù hợp với nhau. Khi cả hai đều là refs, nếu b thay đổi giữa chừng, thì giao dịch sẽ bắt đầu lại và sử dụng các giá trị mới của cả a và b. xem xét sử dụng ensurehàm: clojure.github.io/clojure/clojure.core-api.html#clojure.core/… để làm cho điều này rõ ràng và hiệu quả hơn.
Arthur Ulfeldt

3
Có thể giải thích về những gì Isolated with shared default method có thể được thêm vào để hoàn thành câu trả lời?
Didier A.

1
"Quyền truy cập phối hợp được sử dụng khi hai Danh tính cần được thay đổi cùng nhau ...". Điều đó có nên được "thay đổi"?
Chất gây ung thư

40

Refs dành cho trạng thái cần được đồng bộ giữa các luồng. Nếu bạn cần theo dõi nhiều thứ khác nhau và đôi khi bạn sẽ cần thực hiện các thao tác ghi nhiều thứ cùng một lúc, hãy sử dụng refs. Bất cứ lúc nào bạn có nhiều trạng thái khác nhau, sử dụng ref không phải là một ý kiến ​​tồi.

Nguyên tử dành cho trạng thái độc lập cần được đồng bộ giữa các luồng. Nếu bạn không bao giờ cần phải thay đổi trạng thái của nguyên tử và bất kỳ thứ gì khác cùng một lúc, thì việc sử dụng nguyên tử là an toàn (đặc biệt, nếu chỉ có một trạng thái trong toàn bộ chương trình, bạn có thể đặt nó vào nguyên tử) . Như một ví dụ không nhỏ, nếu bạn đang cố gắng lưu vào bộ nhớ cache các giá trị trả về của một hàm (tức là ghi nhớ nó), thì việc sử dụng nguyên tử có lẽ là an toàn - trạng thái là vô hình với mọi thứ bên ngoài hàm, vì vậy bạn không cần phải lo lắng về sự thay đổi trạng thái bên trong hàm làm rối tung mọi thứ.

Điểm chính của đại lý là chúng chạy trong một chuỗi khác. Bạn có thể lấy giá trị của tác nhân và yêu cầu nó áp dụng một hàm cho giá trị của nó, nhưng bạn không biết khi nào hàm sẽ chạy hoặc giá trị nào mà hàm sẽ được áp dụng.

Vars dành cho khi bạn cần lưu trữ thứ gì đó trên cơ sở mỗi luồng. Nếu bạn có một chương trình đa luồng và mỗi luồng cần trạng thái riêng tư của nó, hãy đặt trạng thái đó trong một var.

Đối với các ví dụ trong thế giới thực, nếu bạn cung cấp ví dụ về những gì bạn đang cố gắng làm, chúng tôi có thể cho bạn biết bạn nên sử dụng những gì.


32

Khi tôi lần đầu tiên đọc về những loại này, tôi cũng đã đấu tranh để hiểu nơi tôi có thể hoặc nên sử dụng từng loại, vì vậy đây là câu trả lời đơn giản bằng tiếng Anh của tôi:

Sử dụng var khi dữ liệu không thay đổi. Điều này xảy ra bất cứ khi nào bạn sử dụng defhoặc hầu hết các chức năng bắt đầu bằng deflike defn.

Sử dụng nguyên tử khi bạn có một mục duy nhất thay đổi. Một ví dụ có thể là một bộ đếm hoặc một vectơ mà bạn muốn thêm các mục vào.

Sử dụng ref khi bạn có hai hoặc nhiều thứ phải thay đổi cùng một lúc. Hãy nghĩ đến "giao dịch cơ sở dữ liệu" nếu bạn đã quen thuộc. Ví dụ điển hình của việc này là chuyển tiền từ tài khoản này sang tài khoản khác. Mỗi tài khoản có thể được lưu trữ trong một ref để có thể thực hiện các thay đổi để có vẻ nguyên tử.

Sử dụng tác nhân khi bạn muốn thay đổi điều gì đó nhưng bạn không quan tâm khi nào. Đây có thể là một tính toán dài hoặc ghi một cái gì đó vào một tệp hoặc ổ cắm. Lưu ý rằng với cái sau bạn nên sử dụng send-off.

Lưu ý: Tôi đánh giá cao rằng có khá nhiều thứ khác cho mỗi thứ nhưng hy vọng điều này sẽ cung cấp cho bạn một điểm khởi đầu.


1
Cảm ơn rất nhiều vì câu trả lời rõ ràng của bạn :-) Giúp một người mới chơi Clojure như tôi khá nhiều.
gosukiwi

27

Tôi đã viết một bài báo với tóm tắt sự khác biệt giữa chúng và giúp chọn khi sử dụng cái nào.

Chia sẻ trạng thái - khi sử dụng vars, nguyên tử, agent và refs?

Tôi hy vọng nó sẽ giúp mọi người tìm kiếm câu trả lời trong chủ đề đó.

Một số phím tắt từ bài viết sau gợi ý @tunaci:

Vars

Vars là toàn cầu cho mọi chủ đề.

Không thay đổi vars sau khi tạo. Về mặt kỹ thuật thì có thể, nhưng đó là một ý tưởng tồi vì nhiều lý do.

Nguyên tử

Chia sẻ quyền truy cập vào trạng thái có thể thay đổi cho mọi chủ đề. Thay đổi xảy ra đồng bộ. Thử lại khi luồng khác thay đổi trạng thái trong quá trình chạy.

Không sử dụng các hàm và hàm không phải là hàm đơn giản với thời gian thực thi lâu dài

Đại lý

Chia sẻ quyền truy cập vào trạng thái có thể thay đổi cho mọi chủ đề. Thay đổi xảy ra không đồng bộ.

Refs

Refs hoạt động tương tự như các giao dịch cơ sở dữ liệu. Viết và đọc được bảo vệ trong dosync. Bạn có thể thao tác trên nhiều refs an toàn trong giao dịch.

Và lưu đồ khi sử dụng cái nào: sơ đồ

Vui lòng xem hình ảnh trên trang web, vì luôn có thể cập nhật.

Nó là một chủ đề phức tạp và dài để đưa ra câu trả lời đầy đủ mà không có bài viết sao chép và quá khứ, vì vậy hãy tha thứ cho tôi, tôi đã chuyển hướng bạn đến trang web :)


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.