【发布时间】:2022-09-24 17:32:12
【问题描述】:
所以我有这个实验代码:
class WorkLoader : Runnable {
private val id : Int
private val listener : Listener?
private val lock : ReentrantLock
private val condition : Condition
private val counter : Counter?
private var isFinished : Boolean
constructor(counter: Counter? = null, listener: Listener? = null) {
id = IdGenerator.getId()
isFinished = false
lock = ReentrantLock()
condition = lock.newCondition()
this.counter = counter
this.listener = listener
}
interface Listener {
fun onWorkStarted(id : Int)
fun onWorkFinished(id : Int, s : String, elapsed : Long)
}
override fun run() {
listener?.onWorkStarted(id)
val startTime = System.currentTimeMillis()
//The loop below just simply loads the CPU with useless stuff, it does nothing important
var s = \"\"
for (i in 1 .. 10_000_000) {
counter?.add()
val c : Char = (i % 95 + 32).toChar()
s += c
if (s.length > 200) {
s = s.substring(1)
}
}
val elapsedTime = System.currentTimeMillis() - startTime
listener?.onWorkFinished(id, s, elapsedTime)
lock.lock()
isFinished = true
condition.signal()
lock.unlock()
}
fun waitTillFinished() {
lock.lock()
while (!isFinished) {
condition.await()
}
lock.unlock()
}
}
以及在 6 个独立线程中同时运行 6 个 WorkLoader 实例的主要功能:
fun main(arguments: Array<String>) {
println(\"Hello World!\")
val workListener = WorkLoaderListener()
val workers = ArrayList<WorkLoader>()
for (i in 1..6) {
val workLoader = WorkLoader(counter = null, workListener)
workers.add(workLoader)
val thread = Thread(workLoader)
thread.start()
}
for (worker in workers) {
worker.waitTillFinished()
}
println(\"End of main thread\")
}
class WorkLoaderListener : WorkLoader.Listener {
override fun onWorkStarted(id: Int) {
println(\"Work started, id:$id ${getFormattedTime()}\")
}
override fun onWorkFinished(id: Int, s: String, elapsed : Long) {
println(\"Work ENDED, id:$id ${getFormattedTime()}, in ${elapsed/1000} s\")
}
}
让所有 6 个线程完成执行需要 8 秒。这是输出:
Hello World!
Work started, id:1 21:12:26.577
Work started, id:0 21:12:26.577
Work started, id:2 21:12:26.577
Work started, id:4 21:12:26.577
Work started, id:5 21:12:26.577
Work started, id:3 21:12:26.577
Work ENDED, id:2 21:12:35.137, in 8 s
Work ENDED, id:1 21:12:35.137, in 8 s
Work ENDED, id:3 21:12:35.215, in 8 s
Work ENDED, id:0 21:12:35.215, in 8 s
Work ENDED, id:5 21:12:35.215, in 8 s
Work ENDED, id:4 21:12:35.231, in 8 s
End of main thread
然而!!!单独线程中只有 1 个 WorkLoader 实例在 1 秒内执行。这使得一个一个地运行这些线程而不是同时午餐它们更有效。 像这样:
for (i in 1..6) {
val workLoader = WorkLoader(counter = null, workListener)
workers.add(workLoader)
val thread = Thread(workLoader)
thread.start()
//just one extra line to wait for the termination before starting another workLoader
workLoader.waitTillFinished() //I understand that the workLoader thread might still be running when this method returns,
// but it doesn\'t matter, the thread is about to die anyway
}
输出:
Hello World!
Work started, id:0 21:23:33.622
Work ENDED, id:0 21:23:35.411, in 1 s
Work started, id:1 21:23:35.411
Work ENDED, id:1 21:23:36.545, in 1 s
Work started, id:2 21:23:36.545
Work ENDED, id:2 21:23:37.576, in 1 s
Work started, id:3 21:23:37.576
Work ENDED, id:3 21:23:38.647, in 1 s
Work started, id:4 21:23:38.647
Work ENDED, id:4 21:23:39.687, in 1 s
Work started, id:5 21:23:39.687
Work ENDED, id:5 21:23:40.726, in 1 s
End of main thread
所以在这种情况下,整个程序的执行在 6 或 7 秒内结束。我有一个带有 12 个逻辑线程的 6 核英特尔 CPU。所以我希望最多在 2 秒内执行所有 6 个线程(当一次全部启动时)。在第一种情况下(一次所有线程),CPU 的利用率飙升至 100%,并且在整个执行期间都保持在那里。在第二种情况下(一次一个线程),CPU 在短时间内飙升至 47%,整个执行速度稍快。
那么多线程有什么意义呢?为什么会这样?感觉拥有超过 1 个工作线程是没有意义的,因为任何额外的线程都会使所有其他线程变慢,无论您有多少 CPU 内核可供使用。如果一个线程能够使用 CPU 的所有内核,那么为什么我的 CPU 在第二种情况下没有达到 100% 负载呢?
-
删除了
[java]标签,因为代码是 Kotlin。 -
你是如何进行测试的?您是否使用了基准测试框架,或者至少进行了任何手动预热? (如果不是,您看到的时间可能根本无法反映您的代码的性能。)
-
我很困惑,但我怀疑您对字符串所做的事情的性质由于某种原因对并行性不太友好。它正在创建可能的新字符串,所以可能会有一些内存和 GC 恶作剧影响它?
标签: multithreading kotlin