Multithreading 如何在Scala中执行多个任务?

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]。期货可以通过多种非阻塞方

我有50000个任务,希望用10个线程执行它们。 在Java中,我应该创建Executers.threadPool(10)并将runnable传递给is,然后等待处理所有。据我所知,Scala对这项任务特别有用,但我无法在文档中找到解决方案

Scala 2.9.3及更高版本 最简单的方法是使用scala.concurrent.Future类和相关的基础结构。
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