문제

배우가 잠을자는 가장 좋은 방법은 무엇입니까? 나는 액터가 데이터베이스의 다른 부분을 유지하려는 에이전트로 설정되어 있습니다 (외부 소스에서 데이터를 가져 오는 것을 포함하여). 여러 가지 이유로 (데이터베이스 또는 통신 및 일반로드 문제를 과부하시키지 않아도) 배우가 각 작업 사이에 잠을 자길 원합니다. 나는 10 명의 배우 대상과 같은 것을보고 있습니다.

액터는 항상 새로운 데이터가 들어 오거나 데이터베이스의 다른 부분으로 전파되기를 기다리는 테이블에 앉아 있기 때문에 거의 무한히 실행됩니다. 아이디어는 데이터베이스가 언제라도 가능한 한 완료되는 것입니다. 제 시간에.

나는 무한 루프와 각 루프의 끝에서 수면으로 이것을 할 수 있지만 http://www.scala-lang.org/node/242 액터는 모든 스레드가 차단 될 때마다 확장되는 스레드 풀을 사용합니다. 그래서 나는 실을 불필요하게 낭비하는 것처럼 각 배우의 자고 나사산이 나쁘다는 것을 상상합니다.

아마도 자체 루프가있는 중앙 액터가 시계에서 가입자에게 메시지를 보내는 (비동기 이벤트 시계 관찰자)를 가질 수 있습니까?

누구든지 비슷한 일을했거나 제안이 있습니까? 추가 (아마도 불필요한) 정보에 대해 죄송합니다.

건배

도움이 되었습니까?

해결책

배우가 잠들게 할 필요가 없습니다 : 사용 loop 그리고 react 각 액터마다 기본 스레드 풀에는 대기 스레드가 있고 액터가 처리 할 메시지가 없음을 의미합니다.

당신이 원하는 경우 일정 배우가 처리 할 수있는 이벤트, 이것은 단일 스레드 스케줄러를 사용하는 데 매우 쉽습니다. java.util.concurrent 유용:

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);
  }
}

이것을 정기적 인 작업을 수행하도록 확장 할 수 있으며, 따라서 사용될 수 있습니다.

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

대상 배우는 단순히 적절한 것을 구현하면됩니다. react 주어진 메시지를 처리하려면 루프. 배우가 필요하지 않습니다.

다른 팁

첫 번째 대답에서 Erlang에게 좋은 점이 있었지만 사라진 것 같습니다. Scala 배우와 동일한 Erlang과 같은 트릭을 쉽게 수행 할 수 있습니다. 예를 들어 스레드를 사용하지 않는 스케줄러를 작성하겠습니다.

import actors.{Actor,TIMEOUT}

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

테스트 클라이언트 액터를 사용하여 테스트하겠습니다 (Scala Repl에서 바로 수행했습니다).

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
  }
} }

스케줄러 실행 :

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

그리고 당신은 이와 같은 것을 볼 것입니다

scala> 1249383399
1249383401
1249383403
1249383405
1249383407

즉, 스케줄러가 예상대로 2 초마다 메시지를 보냅니다. 스케줄러를 멈추자 :

sched ! 'stop

테스트 클라이언트는 타임 아웃을보고하기 시작합니다.

scala> TIMEOUT
TIMEOUT
TIMEOUT

또한 중지하십시오.

test ! 'stop

Lift-Util의 액터링 (Apache License)은 일정 및 ScheduLeatFixEdrate 소스를 가지고 있습니다. 액터 핑 .cala

Scaladoc에서 :

액터링 객체는 액터가 특정 간격으로 주어진 메시지로 핑을 할 수있게합니다. 일정 방법은 필요한 경우 취소 할 수있는 ScheduledFuture 개체를 반환합니다.

불행히도 Oxbow_lakes의 답변에는 두 가지 오류가 있습니다.

하나는 간단한 선언 실수 (긴 시간 대 시간 : 긴)이지만 두 번째는 더 미묘합니다.

Oxbow_lakes는 실행을 선언합니다

def run = actors.Scheduler.execute(f) 

그러나 이것은 때때로 메시지가 사라지게됩니다. 즉, 예정되어 있지만 절대 보내지 않습니다. 실행을 선언합니다

def run = f

나를 위해 그것을 고쳤습니다. 리프트 오틸의 액터링에서 정확한 방식으로 이루어졌습니다.

전체 스케줄러 코드는 다음과 같습니다.

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);
    }
}

Oxbow_Lakes 게시물을 편집하려고했지만 저장할 수 없었습니다 (깨진?). 아직 의견을 제시 할 권리가 없습니다. 따라서 새로운 게시물.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top