Multithreading 提高Scala.PAR操作的并行性水平

Multithreading 提高Scala.PAR操作的并行性水平,multithreading,scala,concurrency,Multithreading,Scala,Concurrency,当我在集合上调用par时,它似乎会创建大约5-10个线程,这对于CPU限制的任务来说是很好的 但有时我会有IO绑定的任务,在这种情况下,我希望有500-1000个线程同时从IO中提取—执行10-15个线程非常慢,我看到我的CPU大多处于空闲状态 如何实现这一点?您可以将阻塞io操作包装在阻塞阻塞中: (0 to 1000).par.map{ i => blocking { Thread.sleep(100) Thread.activeCount()

当我在集合上调用
par
时,它似乎会创建大约5-10个线程,这对于CPU限制的任务来说是很好的

但有时我会有IO绑定的任务,在这种情况下,我希望有500-1000个线程同时从IO中提取—执行10-15个线程非常慢,我看到我的CPU大多处于空闲状态


如何实现这一点?

您可以将阻塞io操作包装在
阻塞
阻塞中:

(0 to 1000).par.map{ i =>
    blocking {
      Thread.sleep(100)
      Thread.activeCount()
    }
}.max // yield 67 on my pc, while without blocking it's 10
但您应该问自己一个问题,是否应该使用并行集合进行IO操作。他们的用例是执行CPU繁重的任务

我建议您考虑使用IO调用的期货。

您还应该考虑使用自定义执行上下文来执行该任务,因为全局执行上下文是一个公共的单体,并且您无法控制哪些代码使用它,以及为此目的。如果使用外部库中的所有线程,则很容易使外部库创建的并行计算无法进行

// or just use scala.concurrent.ExecutionContext.Implicits.global if you don't care
implicit val blockingIoEc: ExecutionContextExecutor = ExecutionContext.fromExecutor(
    Executors.newCachedThreadPool()
) 

def fetchData(index: Int): Future[Int] =  Future {
   //if you use global ec, then it's required to mark computation as blocking to increase threads,
   //if you use custom cached thread pool it should increase thread number even without it
    blocking { 
      Thread.sleep(100)
      Thread.activeCount()
    }
}

val futures = (0 to 1000).map(fetchData)

Future.sequence(futures).onComplete {
    case Success(data) => println(data.max) //prints about 1000 on my pc
}

Thread.sleep(1000)
编辑

还可以使用自定义的ForkJoinPoolForkJoinTaskSupport

import java.util.concurrent.ForkJoinPool //scala.concurrent.forkjoin.ForkJoinPool is deprecated
import scala.util.Random
import scala.collection.parallel

val fjpool = new ForkJoinPool(2) 
val customTaskSupport = new parallel.ForkJoinTaskSupport(fjpool) 

val numbers = List(1,2,3,4,5).par 

numbers.tasksupport = customTaskSupport //assign customTaskSupport

你可以在这里寻找答案——未来是一个很难处理的问题。谢谢你的信息。没有办法为某些并行收集任务指定不同的ec吗?据我所知,没有简单的方法将自己的ec传递给并行收集。检查由Gal Naor提供。有很多方法可以为集合设置并行级别,但在我看来,这些方法的解决方案对我来说似乎有点粗糙和不雅观。