【发布时间】:2020-01-26 20:19:50
【问题描述】:
所以我正在学习 scala 并行编程课程,它挑战我们使用不同的实现来实现框模糊。
其中一个是按行分块图像,另一个是按列分块图像。图像存储为(行主要顺序):
type RGBA = Int
/** Image is a two-dimensional matrix of pixel values. */
class Img(val width: Int, val height: Int, private val data: Array[RGBA]) {
def this(w: Int, h: Int) = this(w, h, new Array(w * h))
def apply(x: Int, y: Int): RGBA = {
data(y * width + x)
}
def update(x: Int, y: Int, c: RGBA): Unit = data(y * width + x) = c
}
这是基本模糊的实现,在所有实现中都是一样的。
def boxBlurKernel(src: Img, x: Int, y: Int, radius: Int): RGBA = {
val pixels = for {
j <- (y - radius to y + radius)
i <- (x - radius to x + radius)
if (i > 0 && i < src.width && j > 0 && j < src.height)
} yield src(i,j)
val reds = pixels.map(red)
val greens = pixels.map(green)
val blues = pixels.map(blue)
val alphas = pixels.map(alpha)
val redComponent = reds.sum / pixels.size
val greenComponent = greens.sum / pixels.size
val blueComponent = blues.sum / pixels.size
val alphaComponent = alphas.sum / pixels.size
rgba(redComponent,greenComponent,blueComponent,alphaComponent)
}
现在我们实现一个垂直模糊的实现——
def blur(src: Img, dst: Img, from: Int, end: Int, radius: Int): Unit = {
val imageHeight = src.height
val xCoordinates: Seq[Int] = from until end
val yCoordinates: Seq[Int] = 0 until imageHeight
for {
xCoordinate <- xCoordinates
yCoordinate <- yCoordinates
} yield dst.update(xCoordinate, yCoordinate, boxBlurKernel(src, xCoordinate, yCoordinate, radius))
}
def parBlur(src: Img, dst: Img, numTasks: Int, radius: Int): Unit = {
val imageWidth = src.width
val boundaries = linspace(0, imageWidth, numTasks + 1).map(_.toInt).toScalaVector.sliding(2)
val tasks = boundaries.toList.map { case Seq(from, end) => task {
blur(src, dst, from, end, radius)
}
}
tasks.foreach(_.join())
}
然后我们实现水平模糊
def blur(src: Img, dst: Img, from: Int, end: Int, radius: Int): Unit = {
val imageWidth = src.width
val xCoordinates = 0 until imageWidth
val yCoordinates = from until end
for {
yCoordinate <- yCoordinates
xCoordinate <- xCoordinates
} yield dst.update(xCoordinate, yCoordinate, boxBlurKernel(src, xCoordinate, yCoordinate, radius))
}
def parBlur(src: Img, dst: Img, numTasks: Int, radius: Int): Unit = {
val imageHeight = src.height
val boundaries = linspace(0, imageHeight, numTasks + 1).map(_.toInt).toScalaVector.sliding(2)
boundaries.toList.map {
case Seq(from: Int, end: Int) => task(from, end, blur(src, dst, from, end, radius))
}.foreach(_.join())
}
现在,由于图像以行主要格式存储,因此预计水平模糊会更有效地利用处理器缓存,并且应该比垂直模糊计时快一些。 但是,我发现相反的结果。
垂直框模糊时间 -
[info] Running (fork) scalashop.VerticalBoxBlurRunner
fork/join blur time: 2281.5884644 ms
水平框模糊时间 -
[info] Running (fork) scalashop.HorizontalBoxBlurRunner
fork/join blur time with number of tasks = 32: 2680.8516574 ms
我正在使用 scalameter 和 Mac OS 2.2 GHz 运行这些基准测试
task 并行原语依次返回 ForkJoinTask。
【问题讨论】: