在actor中调用Thread.sleep

时间:2013-11-09 14:16:54

标签: multithreading scala akka actor

我有一个函数重试,基本上看起来像这样(简化):

object SomeObject {
 def retry[T](n: Int)(fn: => T): Option[T] = {
    val res = try {
      Some(fn)
    } catch {
      case _: Exception => None
    }

    res match {
      case Some(x) => Some(x)
      case None => 
        if (n > 1) 
          //make it sleep for a little while
          retry(n - 1)(fn) 
        else None
    }
  }
}

我需要在尝试之间暂停一下。据我所知,在演员中调用Thread.sleep(123)是不可接受的:

class MyActor extends Actor {
  //......
  def someFunc = {
    Thread.sleep(456) // it's not acceptable in an actor, there is another way to do it
  }

}

显然,我不知道客户是否会在演员中使用SomeObject.retry

class MyActor extends Actor {
  //......
  def someFunc = {
    SomeObject.retry(5)(someRequestToServer) // ops, SomeObject.retry uses Thread.sleep!
  }

}

所以,如果我只是添加:

res match {
      case Some(x) => Some(x)
      case None => 
        if (n > 1) 
          //make it sleep for a little while
          Thread.sleep(123) // ops, what if it's being called inside an actor by a client?!
          retry(n - 1)(fn) 
        else None
    }
  }
它不会是明智的,不是吗?如果没有,我该怎么办?

1 个答案:

答案 0 :(得分:5)

是的,调用Thread.sleep是一个坏主意,因为在actor系统中,线程通常是Actors之间共享的有限资源。你不希望一个Actor调用sleep并从其他Actors中占用一个Thread。

您应该做的是使用Scheduler(请参阅docs)让您的演员在将来的某个时间向自己发送消息以重试。为此,您必须将重试代码移出SomeObject并移至Actor

class MyActor extends Actor {

  import context.system.dispatcher

  def receive = {
    case DoIt(retries) if retries > 0 => 
      SomeObject.attempt(someRequestToServer) match {
        case Some(x) => ...
        case None => 
          context.system.scheduler.scheduleOnce(5.seconds, self, DoIt(retries - 1))
      }
  }

}

然后,如果您在Actor系统之外使用SomeObject.try

def attempt(retries: Int) = {
  SomeObject.attempt(someRequestToServer) match {
    case Some(x) => ...
    case None if retries > 0 => {
      Thread.sleep(123)
      attempt(retries - 1)
    }
  }
}

SomeObject.attempt的位置:

object SomeObject {
  def attempt[T](fn: => T): Option[T] =
    try {
      Some(fn)
    } catch {
      case _: Exception => None
    }
}