2009-08-03 37 views
15

Cách tốt nhất để diễn viên ngủ là gì? Tôi có các diễn viên được thiết lập làm đại lý muốn duy trì các phần khác nhau của cơ sở dữ liệu (bao gồm việc lấy dữ liệu từ các nguồn bên ngoài). Vì một số lý do (bao gồm không quá tải cơ sở dữ liệu hoặc truyền thông và các vấn đề tải chung), tôi muốn các diễn viên ngủ giữa mỗi hoạt động. Tôi đang xem một cái gì đó giống như 10 đối tượng diễn viên.Diễn viên đang ngủ?

Các diễn viên sẽ chạy vô hạn, vì sẽ luôn có dữ liệu mới, hoặc ngồi trong bàn chờ để được truyền sang các phần khác của cơ sở dữ liệu, vv có thể tại bất kỳ thời điểm nào.

Tôi có thể làm điều này với vòng lặp vô hạn và ngủ ở cuối mỗi vòng lặp, nhưng theo http://www.scala-lang.org/node/242 diễn viên sử dụng một nhóm luồng được mở rộng bất cứ khi nào tất cả các chuỗi bị chặn. Vì vậy, tôi tưởng tượng một Thread.sleep trong mỗi diễn viên sẽ là một ý tưởng tồi như sẽ lãng phí chủ đề không cần thiết.

Tôi có lẽ có thể có một diễn viên trung tâm với vòng lặp riêng của mình để gửi tin nhắn tới người đăng ký trên đồng hồ (như các đồng hồ quan sát sự kiện không đồng bộ)?

Có ai đã làm bất kỳ điều gì tương tự hoặc có bất kỳ đề xuất nào không? Xin lỗi cho thông tin thêm (có lẽ thừa).

Cheers

Joe

Trả lời

16

Không cần gây một cách rõ ràng là một diễn viên ngủ: sử dụng loopreact cho mỗi diễn viên có nghĩa là hồ bơi thread cơ bản sẽ có đề chờ đợi trong khi không có thông điệp cho các diễn viên để xử lý.

Trong trường hợp mà bạn muốn lịch sự kiện cho diễn viên của mình để xử lý, điều này là khá dễ dàng sử dụng một lịch trình đơn luồng từ java.util.concurrent tiện ích:

object Scheduler { 
    import java.util.concurrent.Executors 
    import scala.compat.Platform 
    import java.util.concurrent.TimeUnit 
    private lazy val sched = Executors.newSingleThreadScheduledExecutor(); 
    def schedule(f: => Unit, time: Long) { 
    sched.schedule(new Runnable { 
     def run = f 
    }, time , TimeUnit.MILLISECONDS); 
    } 
} 

Bạn có thể mở rộng này để lấy định kỳ công việc và nó có thể được sử dụng như vậy:

val execTime = //... 
Scheduler.schedule({ Actor.actor { target ! message };() }, execTime) 

Sau đó, tác nhân đích của bạn sẽ cần thực hiện một vòng lặp thích hợp để xử lý thông điệp đã cho. Bạn không cần phải ngủ bất kỳ diễn viên nào.

21

Có một điểm tốt cho Erlang trong câu trả lời đầu tiên, nhưng có vẻ như đã biến mất. Bạn có thể thực hiện cùng một thủ thuật giống như Erlang với các diễn viên Scala dễ dàng. Ví dụ. chúng ta hãy tạo ra một lịch trình mà không sử dụng đề:

import actors.{Actor,TIMEOUT} 

def scheduler(time: Long)(f: => Unit) = { 
    def fixedRateLoop { 
    Actor.reactWithin(time) { 
     case TIMEOUT => f; fixedRateLoop 
     case 'stop => 
    } 
    } 
    Actor.actor(fixedRateLoop) 
} 

Và chúng ta hãy kiểm tra nó (tôi đã làm nó ngay trong Scala REPL) sử dụng một diễn viên kiểm tra khách hàng:

case class Ping(t: Long) 

import Actor._ 
val test = actor { loop { 
    receiveWithin(3000) { 
    case Ping(t) => println(t/1000) 
    case TIMEOUT => println("TIMEOUT") 
    case 'stop => exit 
    } 
} } 

Run scheduler:

import compat.Platform.currentTime 
val sched = scheduler(2000) { test ! Ping(currentTime) } 

và bạn sẽ thấy một cái gì đó như thế này

scala> 1249383399 
1249383401 
1249383403 
1249383405 
1249383407 

có nghĩa là công cụ lên lịch của chúng tôi sẽ gửi thư mỗi 2 giây như mong đợi.Hãy dừng scheduler:

sched ! 'stop 

khách hàng thử nghiệm sẽ bắt đầu báo cáo timeout:

scala> TIMEOUT 
TIMEOUT 
TIMEOUT 

dừng nó là tốt:

test ! 'stop 
+2

+1 để hiển thị nhập và có ví dụ về REPL-runnable. – opyate

+0

+1 mẹo này hoạt động hoàn hảo –

4

ActorPing (Apache License) từ lift-util có lịch biểu và lịch biểuAtFixedRate Nguồn: ActorPing.scala

Từ scaladoc:

Đối tượng ActorPing lên lịch cho một diễn viên được ping-ed với một thông báo cụ thể tại các khoảng thời gian cụ thể. Các phương thức lịch biểu trả lại đối tượng ScheduledFuture có thể bị hủy nếu cần thiết

2

Rất tiếc, có hai lỗi trong câu trả lời của oxbow_lakes.

Một là một lỗi khai báo đơn giản (thời gian dài so với thời gian: Dài), nhưng thứ hai là một số tinh tế hơn.

oxbow_lakes tuyên bố chạy như

def run = actors.Scheduler.execute(f) 

Tuy nhiên điều này dẫn đến thông điệp biến mất bất cứ lúc nào. Đó là: chúng được lên kế hoạch nhưng không bao giờ gửi. Khai báo chạy dưới dạng

def run = f 

sửa nó cho tôi. Nó được thực hiện theo cách chính xác trong ActorPing của lift-util.

Mã toàn bộ lịch trình trở thành:

object Scheduler { 
    private lazy val sched = Executors.newSingleThreadedScheduledExecutor(); 
    def schedule(f: => Unit, time: Long) { 
     sched.schedule(new Runnable { 
      def run = f 
     }, time - Platform.currentTime, TimeUnit.MILLISECONDS); 
    } 
} 

Tôi cố gắng để sửa oxbow_lakes bưu điện, nhưng không thể lưu nó (bị hỏng?), Không làm tôi có quyền bình luận, nêu ra. Do đó, một bài đăng mới.

+0

Tôi đã chỉnh sửa bài đăng của anh ấy, với các chỉnh sửa của bạn và của tôi. –

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