2012-09-13 30 views
6

Tôi đã được bảo rằng (Scala) Các diễn viên không bao giờ thực sự thực hiện hai thao tác cùng một lúc, cho thấy phương thức hành động (hoặc phản ứng? Hoặc nhận?) Vốn đã được đồng bộ hóa. Tôi biết một hoạt động dài trong một phương pháp hành động có thể gây ra các vấn đề chặn, và tôi cho rằng việc truy cập vào hàng đợi tin nhắn phải được đồng bộ theo một cách nào đó ... nhưng ...Hiểu rõ tính chất của các tác nhân trong scala

Điều được đề xuất là một diễn viên nhận được thông báo nó để tăng một truy cập nội bộ sẽ tăng truy cập một cách threadsafe. Không có hai thông báo cập nhật nào được xử lý đồng thời và do đó không có hai thông báo nào có thể cố cập nhật bộ đếm cùng một lúc.

Thuộc tính phản đối trong một diễn viên có vẻ như "trạng thái được chia sẻ".

Có thực sự là một hoạt động như vậy sẽ hoàn toàn an toàn không? Nếu vậy, làm thế nào để một diễn viên sử dụng nhiều máy lõi một cách hiệu quả? Làm thế nào là một diễn viên đa luồng ở tất cả?

Nếu không, cách thành ngữ thích hợp để đếm thư theo cách an toàn mà không cần biến số đồng bộ/biến động là gì?

Trả lời

8

Mô hình diễn viên có thể được sử dụng để cô lập nhà nước có thể thay đổi từ thế giới bên ngoài. Khi bạn có một trạng thái có thể thay đổi (ví dụ như một đăng ký toàn cục của các ID được gán cho nhiều tiến trình đồng thời), bạn có thể bao bọc trạng thái có thể thay đổi đó bên trong một Actor và làm cho khách hàng giao tiếp với Actor thông qua việc truyền thông điệp. Bằng cách đó, chỉ có nam diễn viên truy cập trực tiếp trạng thái có thể thay đổi và như bạn nói, các thông điệp khách hàng xếp hàng để được đọc và xử lý từng cái một. Điều quan trọng đối với tin nhắn là không thay đổi.

Để tránh hàng đợi bị đầy, điều quan trọng là việc xử lý tin nhắn (react, receive, v.v.) càng ngắn càng tốt.nhiệm vụ lâu dài nên được trao tắt để một diễn viên khác:

1. Actor A receives a message M from sender S 
2. A spawns a new actor C 
3. A sends (S, f(M)) to C 
4. In parallel: 
4a. A starts processing the next message. 
4b. C does the long-running or dangerous (IO) task, 
    When finished, sends the result to S, 
    and C terminates. 

Một số lựa chọn thay thế trong quá trình này:

  • C gửi (S, result) trở lại Một người chuyển tiếp đến S
  • A giữ một ánh xạ ActorRef C => (Sender S, Message M)so in case it sees C fail, nó có thể thử lại xử lý M với một diễn viên mới.

Vì vậy, để tóm tắt, một diễn viên là đa luồng đến mức mà nhiều khách hàng có thể gửi nó nhiều tin nhắn từ chủ đề khác nhau, và nó được đảm bảo rằng các diễn viên sẽ xử lý tất cả các thông báo serially (mặc dù thứ tự có thể tùy thuộc vào các ràng buộc không quá nghiêm ngặt khác nhau). Lưu ý rằng khi Mã số react của diễn viên , trong một thời điểm nhất định, nó chỉ được thực hiện trên một chuỗi cho trước (bạn có thể hình dung rằng diễn viên nhảy từ chuỗi này sang luồng khác khi trình lập lịch biểu phù hợp, nhưng điều này là một chi tiết kỹ thuật). Lưu ý: Trạng thái nội bộ vẫn không cần đồng bộ hóa, vì Actors guarantee happens-before semantics giữa các thông báo xử lý.

Tính song song đạt được bằng cách có nhiều diễn viên hoạt động song song, thường tạo thành supervisor hierarchies hoặc balancing workload.

Lưu ý rằng nếu tất cả những gì bạn cần là tính toán đồng thời/không đồng bộ, nhưng bạn không có hoặc có thể loại bỏ trạng thái toàn cầu, Futures are a better composing và khái niệm dễ dàng hơn.

+0

Đây là một lời giải thích tuyệt vời, cảm ơn! – Brian

+0

Câu trả lời hay. Tôi sẽ thêm rằng trong khi các phản ứng của một diễn viên có thể chạy trên các chủ đề khác nhau (và do đó sẽ 'thường' bị các vấn đề về bộ nhớ), bạn thực sự không cần đồng bộ hóa quyền truy cập vào trạng thái của tác nhân. Điều này là do khung diễn viên đã làm như vậy trước khi thực hiện một diễn viên. Xem http://stackoverflow.com/questions/1031167/should-my-scala-actors-properties-be-marked-volatile –

+0

Rất vui khi được trợ giúp. Régis: Cảm ơn, đã cập nhật văn bản chính xác hơn. – ron

6

"Một diễn viên" không đa luồng, nhưng hệ thống diễn viên thường là. Mỗi tác nhân chỉ thực hiện một hành động cùng một lúc, nhưng khi có nhiều tác nhân, mỗi tác nhân có thể hoạt động trên trạng thái đóng gói tương ứng của nó song song. Thuộc tính truy cập không phải là được chia sẻ trạng thái có thể thay đổi nếu nó không được chia sẻ giữa các tác nhân.

Nếu câu hỏi của bạn là về việc triển khai hệ thống diễn viên, có thể cấu hình được, tức là các diễn viên Scala mặc định có thể được cấu hình để chạy một luồng đơn hoặc trên một nhóm luồng hoặc sử dụng các tác vụ Java ForkJoin. Tôi tìm thấy nguồn scala.actors rất dễ đọc, vì vậy tôi khuyên bạn nên xem nếu bạn muốn hiểu những gì đang xảy ra.

+0

+1 cho con trỏ tới mã nguồn Scala. Nó độc đáo cho thấy khái niệm. – sourcedelica

2

Bạn có thể sử dụng một diễn viên riêng để thực hiện việc đếm. Khi một diễn viên nhận được một tin nhắn, nó có thể gửi một tin nhắn tới một diễn viên đếm (singleton). Bằng cách này bạn có thể có nhiều nhân viên công việc và vẫn tin nhắn.

Akka có thứ gọi là Agents có thể hữu ích trong ngữ cảnh này.

val counter = Agent(0) 
counter send (_ + 1) 

http://doc.akka.io/docs/akka/2.0.2/scala/agents.html

+0

Tác nhân được thiết kế riêng cho trường hợp sử dụng này. Về mặt luồng và đồng bộ hóa chúng hoạt động giống như các tác nhân viết và AtomicX để đọc. – sourcedelica

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