2013-06-22 22 views
16

Scala'da, JavaScript'in setTimeout gibi bir işlevini geciktirmenin en kolay yolu nedir? İdeal olarak, geciktirilmiş uygulama başına yumurtlama ipliği olmaksızın, yani sıralı uygulama. Bulduğum en yakın nokta Akka'nın Scheduler'du, ama bu bir aşırı sıkıcıydı.Gecikmeli işlev yürütme

Test amaçlı olarak binlerce bağlantı açıyorum, sonra 10 saniye içinde yanıt alıyorlar. Node.js 'de göründüğü gibi:

http.createServer(function (req, res) { 
    res.writeHead(200, {'Content-Type': 'text/plain'}); 
    setTimeout(function() {res.end('Hello World\n');}, 10000); 
}).listen(8080, '127.0.0.1'); 

Ama aynı şeyi yapan en yakın Scala versiyonu ne olurdu? res.end'un birden fazla iş parçacığında yürütülüp yürütülmeyeceği veya tek bir kuyrukta sıralanacağı umrumda değil. Çok basitçe basit için soruya cevap uçaksavar alma bıktınız

+1

Olası yinelenen, bu cevap yardımcı olur eminim: http://stackoverflow.com/a/16629357/1296806 ancak test için bir müptezel kerelik istiyorum belki. –

+0

Bu diğer soruya da bir göz atabilirsiniz: http://stackoverflow.com/questions/16359849/scala-scheduledfuture –

cevap

20

, burada standart JVM deyimler şunlardır: Orada standart kütüphanesinde gecikmiş bir görev zamanlama için hiçbir API, ancak bir yapabilirsiniz

$ scala 
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_65). 
Type in expressions for evaluation. Or try :help. 

scala> import java.util.{Timer,TimerTask} 
import java.util.{Timer, TimerTask} 

scala> val timer = new Timer 
timer: java.util.Timer = [email protected] 

scala> def delay(f:() => Unit, n: Long) = timer.schedule(new TimerTask() { def run = f() }, n) 
delay: (f:() => Unit, n: Long)Unit 

scala> delay(() => println("Done"), 1000L) 

scala> Done 


scala> import java.util.concurrent._ 
import java.util.concurrent._ 

scala> val x = Executors.newScheduledThreadPool(2) 
x: java.util.concurrent.ScheduledExecutorService = [email protected] 

scala> x.schedule(new Callable[Int]() { def call = { println("Ran"); 42 }}, 1L, TimeUnit.SECONDS) 
res3: java.util.concurrent.ScheduledFuture[Int] = java.[email protected]3ab0f534 

scala> Ran 

Scala Future'u kullanmak için ExecutionContext sabit bir gecikmeyle.

scala> import scala.concurrent._ 
import scala.concurrent._ 

scala> implicit val xx = new ExecutionContext() { 
    | def reportFailure(t: Throwable) = t.printStackTrace() 
    | def execute(r: Runnable) = x.schedule(new Callable[Unit]() { def call = r.run() }, 1L, TimeUnit.SECONDS) 
    | } 
xx: scala.concurrent.ExecutionContext = [email protected] 

scala> Future(println("hello")) 
res4: scala.concurrent.Future[Unit] = List() 

scala> hello 

scala> Future(42) 
res5: scala.concurrent.Future[Int] = List()     

scala> .value 
res6: Option[scala.util.Try[Int]] = Some(Success(42)) 

Yoksa Scheduled Executor in Scala

eski bir liner en kanonik cevaptır Akka en zamanlayıcı, kullanabilirsiniz:

En basit hala future { blocking(Thread.sleep(10000L)); "done" }

ama bir yere istedim Sadece karşımıza çıkan bu adam için reklam, size bir ilerleme göstergesi veya ara değer verir. Keşke farklı bir ismi olsaydı, hepsi bu.

scala> import concurrent._ 
import concurrent._ 

scala> import ExecutionContext.Implicits._ 
import ExecutionContext.Implicits._ 

scala> import duration._ 
import duration._ 

scala> val deadline = 60.seconds.fromNow 
deadline: scala.concurrent.duration.Deadline = Deadline(38794983852399 nanoseconds) 

scala> new DelayedLazyVal(() => deadline.timeLeft.max(Duration.Zero), blocking { 
    | Thread.sleep(deadline.timeLeft.toMillis) 
    | Console println "Working!" 
    | }) 
res9: scala.concurrent.DelayedLazyVal[scala.concurrent.duration.FiniteDuration] = [email protected] 

scala> res9() 
res10: scala.concurrent.duration.FiniteDuration = 23137149130 nanoseconds 

scala> res9.isDone 
res11: Boolean = false 

scala> res9() 
res12: scala.concurrent.duration.FiniteDuration = 12499910694 nanoseconds 

scala> res9() 
res13: scala.concurrent.duration.FiniteDuration = 5232807506 nanoseconds 

scala> Working! 


scala> res9.isDone 
res14: Boolean = true 

scala> res9() 
res15: scala.concurrent.duration.FiniteDuration = 0 days 

Burada alternatif bir formül, bir gecikmeden sonra bir değer hesaplamak için. Left'u kullanarak hala Left zamanınız var.

scala> new DelayedLazyVal(()=> if (deadline.hasTimeLeft) Left(deadline.timeLeft) else 
    | Right("Working!"), blocking(Thread.sleep(deadline.timeLeft.toMillis))) 
res21: scala.concurrent.DelayedLazyVal[Product with Serializable with scala.util.Either[scala.concurrent.duration.FiniteDuration,String]] = [email protected] 

scala> res21() 
res22: Product with Serializable with scala.util.Either[scala.concurrent.duration.FiniteDuration,String] = Left(28553649064 nanoseconds) 

scala> res21() 
res23: Product with Serializable with scala.util.Either[scala.concurrent.duration.FiniteDuration,String] = Left(9378334087 nanoseconds) 

scala> res21.isDone 
res24: Boolean = false 

scala> res21() 
res25: Product with Serializable with scala.util.Either[scala.concurrent.duration.FiniteDuration,String] = Right(Working!) 

scala> res21.isDone 
res26: Boolean = true 
+6

, 10 saniyede uyuyan binlerce iş parçacığına neden olmaz mı? –

+3

Engelleme olmayan bir çözüm var mı? –

+0

@OlegMikheev Evet. –