JavaFx / Kotlin中的多线程图像渲染

时间:2017-08-03 17:25:40

标签: java multithreading javafx kotlin coroutine

我尝试使用所有CPU内核尽快填充图像(在JavaFx中),但我遇到了一些问题。下面是我能想出的最小的例子来重现问题。

当我使用join()函数创建的Job上调用launch时,图像呈现正确,但显然只使用了一个CPU内核?那是为什么?

enter image description here

另一方面,当我没有在返回的作业上调用join()时,所有CPU内核都被使用,但显然,图像渲染不正确,因为父方法不会。等待工作完成:

enter image description here

任何方式我都可以让它填满所有内核但看起来仍然正确吗?

package com.serious.business

import javafx.animation.AnimationTimer
import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.canvas.Canvas
import javafx.scene.image.WritableImage
import javafx.scene.layout.Pane
import javafx.stage.Stage
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.runBlocking

class ImageTestApp: Application() {

    val w = 800.0
    val h = 800.0
    val image = WritableImage(w.toInt(), h.toInt())
    var blue: Double = 0.0

    override fun start(primaryStage: Stage) {
        val canvas = Canvas(w, h)
        val scene = Scene(Pane(canvas), w, h)
        primaryStage.scene = scene
        primaryStage.title = "Threaded image write"
        primaryStage.show()

        object: AnimationTimer() {
            override fun handle(now: Long) {
                blue += 0.2
                blue %= 1

                runBlocking {
                    renderGradient(image, blue)
                }
                canvas.graphicsContext2D.drawImage(image, 0.0, 0.0)
            }
        }.start()
    }
}

suspend fun renderGradient(image: WritableImage, blue: Double) {
    val width = image.width
    val height = image.height

    val slices = 8
    val band = width.toInt() / slices

    val writer = image.pixelWriter

    for (i in 0..slices-1) {
        val startX = i * band
        val endX = startX + band - 1

        launch(CommonPool) {
            for (x in startX..endX) {
                for (y in 0..height.toInt() - 1) {
                    val color = Color(
                        x.toDouble() / width,
                        y.toDouble() / height,
                        blue,
                        1.0
                    )
                    writer.setColor(x, y, color)
                }
            }
        }.join()
    }
}

fun main(args: Array<String>) {
    Application.launch(ImageTestApp::class.java, *args)
}

0 个答案:

没有答案