Scala 中的后台任务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6334566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 03:05:17  来源:igfitidea点击:

Background task in Scala

multithreadingscala

提问by Jeb

I have a cache I want to periodically check and prune. In Java, I'd do the following:

我有一个缓存,我想定期检查和修剪。在 Java 中,我会执行以下操作:

new Thread(new Runnable() {
  void run() {
    while (true) { 
      Thread.sleep(1000);
      // clear the cache's old entries
    }
  }
}).start();

Sure, I'd have some issues with thread-safe types to use as the cache, but putting that aside, my question is simple. What's the Scala way of running a recurring background task -- something you don't want running in the application's main thread?

当然,我在使用线程安全类型作为缓存时会遇到一些问题,但把它放在一边,我的问题很简单。运行循环后台任务的 Scala 方式是什么——您不希望在应用程序的主线程中运行的任务?

I've used actors a bit and I guess my problem in this scenario is that I don't have anything to generate a message that it's time to clear the cache. Or rather, the only way I can imagine to generate those messages is to create a thread to do it...

我已经使用了一些演员,我想我在这种情况下的问题是我没有任何东西可以生成一条消息,该消息是时候清除缓存了。或者更确切地说,我能想象生成这些消息的唯一方法是创建一个线程来执行它...

EDIT: I need people to vote on answers -- they all look good to me

编辑:我需要人们对答案进行投票——他们对我来说都很好

采纳答案by k4200

There are many ways to do that, but I would do something simple like the following.

有很多方法可以做到这一点,但我会做一些简单的事情,如下所示。

import scala.concurrent.ops._

spawn {
  while (true) { 
    Thread.sleep(1000);
    // clear the cache's old entries
  }
}

Hope this helps.

希望这可以帮助。

回答by paradigmatic

You could use Akka Scheduler, which allows you to send a reccuring message to an (akka) actor doing the job. From the doc, just use:

您可以使用Akka Scheduler,它允许您向执行该工作的(akka)actor 发送重复消息。从文档中,只需使用:

import akka.actor.Scheduler

//Sends messageToBeSent to receiverActor after initialDelayBeforeSending and then after each delayBetweenMessages
Scheduler.schedule(receiverActor, messageToBeSent, initialDelayBeforeSending, delayBetweenMessages, timeUnit)

回答by Jus12

Futures is a simple way to do it without explicitly starting a new thread

Futures 是一种简单的方法,无需显式启动新线程

import scala.actors.Futures._

// main thread code here

future {
   // second thread code here
}

// main thread code here

回答by Bill

spawnis good but note that your sample code works in Scala too:

spawn很好,但请注意,您的示例代码也适用于 Scala:

new Thread(new Runnable() {
  override def run() {
    while (true) { 
      Thread.sleep(1000);
      // clear the cache's old entries
    }
  }
}).start();

Just clean it up with an implicit conversion:

只需使用隐式转换清理它:

implicit def funcToRunnable(f: => ()) = new Runnable() { override def run() { f() } }

new Thread{
  while(true) {
    Thread.sleep(1000);
    // blah
  }
}.start()

回答by Johan Prinsloo

With Actors without tying up a thread:

使用 Actors 而不占用线程:

import actors.{TIMEOUT, Actor}
import actors.Actor._

private case class Ping( client: Actor, update: Int )
private case class Pulse()
case class Subscribe( actor: Actor )
case class Unsubscribe( actor: Actor )

class PulseActor extends Actor {
  def act = eventloop {
        case ping: Ping => { sleep(ping.update); ping.client ! Pulse }
  }
  def sleep(millis: Long) =
    receiveWithin(millis) {
      case TIMEOUT =>
  }
}

class ServiceActor extends Actor {

  var observers: Set[Actor] = Set.empty
  val pulseactor = new PulseActor
  val update = 2000

  def act = {
    pulseactor.start
    pulseactor ! new Ping( this, update )
    loop {
      react {
        case sub: Subscribe => observers += sub.actor
        case unsub: Unsubscribe => observers -= unsub.actor
        case Pulse => pulse
      }
    }
  }


  def pulse {  
    //cpuload = CPUprofile.getCPUload.getOrElse{ List(0.0) }  //real work
    observers foreach { observer => observer ! "CPUloadReport( cpuload )" }
    pulseactor ! Ping(this, update)
  }
}

object Exercise extends App {
  val deamon = new ServiceActor
  deamon.start
}

回答by Jus12

As of Scala 2.11.x, Akka actors seems to be the best way to do this IMHO. First create a task scheduling library:

从 Scala 2.11.x 开始,Akka 演员似乎是做到这一点恕我直言的最佳方式。首先创建一个任务调度库:

import akka.actor.ActorSystem
import scala.language.postfixOps
import scala.concurrent.duration._
val actorSystem = ActorSystem()
val scheduler = actorSystem.scheduler
implicit val executor = actorSystem.dispatcher

// do once after period millis
def doOnce(fn: => Unit, period:Long) = scheduler.scheduleOnce(period milliseconds)(fn) 
// do regularly every period millis starting now
def doRegularly(fn: => Unit, period:Long) = scheduler.schedule(0 seconds, period milliseconds)(fn)
// do regularly every period millis if whileFn is true, starting now 
def doWhile(fn: => Unit, whileFn: => Boolean, period:Long) {
 if (whileFn) {
    fn
    doOnce(doWhile(fn, whileFn, period), period)
 }
}

Then use this as:

然后将其用作:

doRegularly({
  println("hello world!")
}, 1000) // repeat every 1000 millisecs

doWhile({
  println("Sleeping!")
}, whileDaylight, 1000) // repeat every 1000 millisecs whileDaylight is true