Multithreading 如何在Scala中执行多个任务?
我有50000个任务,希望用10个线程执行它们。 在Java中,我应该创建Executers.threadPool(10)并将runnable传递给is,然后等待处理所有。据我所知,Scala对这项任务特别有用,但我无法在文档中找到解决方案 Scala 2.9.3及更高版本 最简单的方法是使用scala.concurrent.Future类和相关的基础结构。Multithreading 如何在Scala中执行多个任务?,multithreading,scala,concurrency,Multithreading,Scala,Concurrency,我有50000个任务,希望用10个线程执行它们。 在Java中,我应该创建Executers.threadPool(10)并将runnable传递给is,然后等待处理所有。据我所知,Scala对这项任务特别有用,但我无法在文档中找到解决方案 Scala 2.9.3及更高版本 最简单的方法是使用scala.concurrent.Future类和相关的基础结构。scala.concurrent.future方法异步计算传递给它的块,并立即返回表示异步计算的future[a]。期货可以通过多种非阻塞方
scala.concurrent.future
方法异步计算传递给它的块,并立即返回表示异步计算的future[a]
。期货可以通过多种非阻塞方式进行操作,包括映射、平面映射、过滤、恢复错误等
例如,下面是一个创建10个任务的示例,其中每个任务休眠任意时间,然后返回传递给它的值的平方
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
val tasks: Seq[Future[Int]] = for (i <- 1 to 10) yield future {
println("Executing task " + i)
Thread.sleep(i * 1000L)
i * i
}
val aggregated: Future[Seq[Int]] = Future.sequence(tasks)
val squares: Seq[Int] = Await.result(aggregated, 15.seconds)
println("Squares: " + squares)
import scala.actors.Futures._
val tasks = for (i <- 1 to 10) yield future {
println("Executing task " + i)
Thread.sleep(i * 1000L)
i * i
}
val squares = awaitAll(20000L, tasks: _*)
println("Squares: " + squares)
您需要查看Scala actors库或Akka。Akka有更清晰的语法,但两者都可以 所以听起来你需要创建一个参与者池,他们知道如何处理你的任务。Actor基本上可以是具有receive方法的任何类-来自Akka教程(): 您需要创建一个参与者实例池,并将任务作为消息发送给它们。以下是关于Akka演员池的帖子,可能会有所帮助: 在您的情况下,每个任务一个参与者可能是合适的(与线程相比,参与者非常轻量级,因此您可以在单个VM中拥有很多参与者),或者您可能需要在它们之间进行更复杂的负载平衡 编辑: 使用上面的示例actor,向其发送消息非常简单:
myActor ! "test"
然后,参与者将“接收到的测试”输出到标准输出
消息可以是任何类型,当与Scala的模式匹配相结合时,您就有了一个强大的模式来构建灵活的并发应用程序
一般来说,Akka演员在线程共享方面会“做正确的事情”,对于OP的需求,我认为默认设置是可以的。但如果需要,可以将参与者应使用的调度程序设置为以下几种类型之一:
* Thread-based
* Event-based
* Work-stealing
* HawtDispatch-based event-driven
为参与者设置调度程序很简单:
class MyActor extends Actor {
self.dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher("thread-pool-dispatch")
.withNewThreadPoolWithBoundedBlockingQueue(100)
.setCorePoolSize(10)
.setMaxPoolSize(10)
.setKeepAliveTimeInMillis(10000)
.build
}
看
通过这种方式,您可以限制线程池的大小,但同样,原始用例可能会满足于使用默认dispatchers的50K Akka actor实例,并且可以很好地并行化
这只不过是Akka能做的表面而已。它为Scala语言带来了许多Erlang提供的功能。参与者可以监视其他参与者并重新启动它们,从而创建自愈应用程序。Akka还提供软件事务内存和许多其他功能。它可以说是Scala的“杀手级应用”或“杀手级框架”。如果你想“用10个线程执行它们”,那么就使用线程。Scala的演员模型通常是人们在说Scala有利于并发时所说的,它隐藏了这样的细节,所以您不会看到它们
使用演员,或者期货,你所拥有的只是简单的计算,你只需要创建50000个演员,然后让他们运行。您可能会遇到问题,但它们的性质不同。下面是另一个答案,与mpilquist的响应类似,但没有弃用的API,并且通过自定义ExecutionContext包含线程设置:
import java.util.concurrent.Executors
import scala.concurrent.{ExecutionContext, Await, Future}
import scala.concurrent.duration._
val numJobs = 50000
var numThreads = 10
// customize the execution context to use the specified number of threads
implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(numThreads))
// define the tasks
val tasks = for (i <- 1 to numJobs) yield Future {
// do something more fancy here
i
}
// aggregate and wait for final result
val aggregated = Future.sequence(tasks)
val oneToNSum = Await.result(aggregated, 15.seconds).sum
导入java.util.concurrent.Executors
导入scala.concurrent.{ExecutionContext,wait,Future}
导入scala.concurrent.duration_
val numJobs=50000
var numThreads=10
//自定义执行上下文以使用指定数量的线程
隐式val ec=ExecutionContext.fromExecutor(Executors.newFixedThreadPool(numThreads))
//定义任务
val任务=用于(我不需要执行10个任务。我有50000个任务,希望用10个线程执行它们。使用futures时,默认情况下,任务在fork/join调度程序中执行,该调度程序为JVM报告的每个处理器最多分配2个线程。最大线程数可以通过actors.corePoolSize系统属性或整个sched来增加uler可以被替换。有关详细信息,请参阅Actor的ScalaDoc。谢谢,顺便问一下,您使用的构造语法是什么:“tasks:*”?将tasks变量转换为awaitAll上的var args调用的*语法。awaitAll方法接受var arg Future[Any],而tasks变量是IndexedSeq[Future[Int]].Adding*告诉编译器将任务扩展为varargs。请参阅本文中的Akka示例!:)您如何处理任务失败,任务是否依赖于状态,顺序,以及为什么需要固定线程池(如果您希望获得尽可能高的并行性,请选择可用的内核)这个问题与这个问题不相关吗?答案似乎简单多了?
import java.util.concurrent.Executors
import scala.concurrent.{ExecutionContext, Await, Future}
import scala.concurrent.duration._
val numJobs = 50000
var numThreads = 10
// customize the execution context to use the specified number of threads
implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(numThreads))
// define the tasks
val tasks = for (i <- 1 to numJobs) yield Future {
// do something more fancy here
i
}
// aggregate and wait for final result
val aggregated = Future.sequence(tasks)
val oneToNSum = Await.result(aggregated, 15.seconds).sum