- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一组任务。除了少数大型任务外,每个此类任务通常都相当小。最初我有一个 Future
每个任务。然而,这导致我不得不为少数 Futures
等待相当长的时间。在空闲状态下有大量 CPU 的更大任务。我想通过检查任务是否超过特定大小来改变这一点,如果是,则将任务再次拆分为多个 Futures
解决一个子任务。然而,这会导致更糟糕的表现,因为第一组 future 突然按顺序执行。没有任何任务或子任务是相关的,因此可以相互独立地解决。
以下是此行为的概念证明。在 Scala 2.13.4 中测试。
import scala.concurrent.{Await, Future, blocking}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.sys.process._
object Main {
val workSet : List[Int] = List(
3000,
3000,
3000,
12000,
3000,
3000,
3000,
12000,
3000,
3000,
3000,
3000,
3000,
)
def stupidWait(wait : Int) : Int = {
println(s"waiting for $wait")
val start = System.currentTimeMillis()
while ( (start + wait) > System.currentTimeMillis()) {}
1
}
def smartWait(wait : Int) : Int = {
val work = if(wait > 3000) {
List(3000,3000,3000,3000)
} else {
List(3000)
}
println(s"smart working with ${work}")
val future = Future.sequence {
work.map {
wait => Future { stupidWait(wait) }
}
}
Await.ready(future, Inf)
1
}
def time() : String = {
"date".!!
}
def main(args : Array[String]) : Unit = {
println(s"${time()} dumb start")
val futureI = Future.sequence {
workSet.map {
wait => Future { stupidWait(wait) }
}
}
Await.ready(futureI,Inf)
println(s"${time()} dumb end")
println(s"${time()} smart start")
val futureII = Future.sequence {
workSet.map {
wait => Future { smartWait(wait) }
}
}
Await.ready(futureII,Inf)
println(s"${time()} smart end")
}
}
输出是:
Thu Mar 4 08:09:42 PM CET 2021
dumb start
...
Thu Mar 4 08:09:54 PM CET 2021
dumb end
Thu Mar 4 08:09:54 PM CET 2021
smart start
...
Thu Mar 4 08:10:39 PM CET 2021
smart end
我原以为智能等待至少会一样快甚至更快,因为较大的等待时间现在被分成 4 个潜在的并行等待时间。然而事实并非如此。
最佳答案
执行程序可用的线程数受限于默认情况下您拥有的内核数(并行运行比执行它们的内核数更多的东西通常毫无意义)。
我想,你可能有 8 个内核。因此,前 8 个等待立即开始,其他 5 个在排队。然后 3 秒后 6 个线程完成它们的任务,并拿起剩余的 5 个。因此,再过 3 秒后,除了两个更大的任务之外,其他所有任务都完成了,它们继续旋转 6 秒。
现在,“(显然不是那么)智能等待”会发生什么?
我在输出中添加了自开始和线程名称以来的秒数,以便更轻松地跟踪正在发生的事情:
0: scala-execution-context-global-16: smart working with List(3000)
0: scala-execution-context-global-18: smart working with List(3000)
0: scala-execution-context-global-21: smart working with List(3000, 3000, 3000, 3000)
0: scala-execution-context-global-19: smart working with List(3000)
0: scala-execution-context-global-17: smart working with List(3000, 3000, 3000, 3000)
0: scala-execution-context-global-14: smart working with List(3000)
0: scala-execution-context-global-20: smart working with List(3000)
0: scala-execution-context-global-15: smart working with List(3000)
0: scala-execution-context-global-22: waiting for 3000
3: scala-execution-context-global-22: waiting for 3000
3: scala-execution-context-global-20: waiting for 3000
6: scala-execution-context-global-22: waiting for 3000
6: scala-execution-context-global-20: waiting for 3000
9: scala-execution-context-global-20: waiting for 3000
9: scala-execution-context-global-22: waiting for 3000
12:
12: scala-execution-context-global-22: waiting for 3000
15: scala-execution-context-global-20: waiting for 3000
15: scala-execution-context-global-17: smart working with List(3000)
15: scala-execution-context-global-21: waiting for 3000
15: scala-execution-context-global-22: waiting for 3000
18: scala-execution-context-global-20: waiting for 3000
18: scala-execution-context-global-19: smart working with List(3000)
18: scala-execution-context-global-16: waiting for 3000
18: scala-execution-context-global-21: waiting for 3000
18: scala-execution-context-global-22: smart working with List(3000)
18: scala-execution-context-global-18: smart working with List(3000)
21: scala-execution-context-global-17: waiting for 3000
21: scala-execution-context-global-20: waiting for 3000
21: scala-execution-context-global-16: smart working with List(3000)
21: scala-execution-context-global-15: waiting for 3000
21: scala-execution-context-global-21: waiting for 3000
看,如何首先启动 8 个“智能”任务。它们都被阻塞了,因为池中没有线程来执行内部 future 。
0
的最后一行)。
ForkJoinPool
中有一些非常聪明和复杂的逻辑。用于检测池中的所有线程都被阻塞等待某个条件的实现,并在发生这种情况时启动一个额外的线程(另一个答案中提到的
blocking
用于帮助实现这一点。遵循该建议将使这个测试在大约 3 秒内完成......但是当你需要实际的内核时它是相当无用的 IRL)。它并不总是有效,并且不适用于所有线程池实现。如果您使用了默认执行程序以外的其他执行程序(或以其他方式阻止),则整个过程很可能会在此时被锁定。
Future.traverse(
workSet.flatMap {
case 3000 => Seq(3000)
case => Seq.fill(4)(3000)
}
) { n => Future(stupidWait(n)) }
或者,为了尽量减少对原始代码的更改,只需制作
smartWait
返回 future 而不是等待它,然后在
main
去掉外层
Future
就做
Future.traverse(workSet)(smartWait)
.
关于multithreading - 嵌套 future 导致更差的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66481706/
我有一个数据库,其中所有表都包含 Site 列 (char(4)) 和 PrimaryId 列 (int )。 目前所有表上的聚集索引都是这两列的组合。许多客户只有一个网站,因此在这些情况下,我认为将
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我一直在阅读有关使用 token 进行身份验证的文章。但是,我无法理解 token (JWT) 与 cookie 有何不同。两者都将存储用户信息(作为 token 中的声明),定义了持久性,并将与每个
我首先使用 keras 1.2.0 在 CPU 上运行相同的代码(具有相同的数据),然后在两种代码中运行 keras 2.0.3 . 当我使用 keras 2.0.3 获得 42 的 MSE(均方误差
我是一名优秀的程序员,十分优秀!