《快学scala》习题解答-第二十章-Actor

《快学Scala》(英文版:《Scala for the Impatient》),代码已传github:

https://github.com/vernonzheng/scala-for-the-Impatient

书为第一版。scala为2.11.4,jdk1.7.45,操作系统Mac OS X Yosemite 10.10.1。

第二十章 Actor

20.1
编写一个程序,生成由n个随机数组成的数组(其中n是一个很大的值,比如1000000),然后通过将工作分发给多个actor的同时计算这些数的平均值,每个actor计算区间内的值之和,将结果发送给一个能组合出结果的actor。
如果你在双核或四核处理器上运行这个程序,和单线程的解决方案相比,会快多少?
双核上差不多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import scala.actors.Actor
import scala.actors.Actor._
val taskCount = Runtime.getRuntime().availableProcessors()
case class SumPart(items:Array[Int],partCount:Int)
case class CollectSum(sum:Int,partCount:Int)
def randomArray(num:Int):Array[Int] = {
val result = new Array[Int](num)
for(i <- 0 to num-1) {
result(i) = (Math.random() * num).toInt
}
result
}
val ReduceActor = actor {
var result = 0D
var receiveCount = 0
loop{
receive{
case CollectSum(sum,partCount)=>
receiveCount += 1
result += sum
println(sum)
if(receiveCount>=partCount){
result = result/partCount
println("Actor result:"+result)
exit()
}
}
}
}
val MapActor = actor{
loop{
react{
case SumPart(items,partCount) =>
ReduceActor ! CollectSum(items.sum, partCount)
exit()
}
}
}
def actorMain(num:Int, partCount:Int) = {
val array = randomArray(num)
val startTime = System.currentTimeMillis()
var range = 1
if(array.length>=partCount)
range = array.length/partCount
var start = 0
var end = 0
var flag = false
MapActor.start()
while(!flag){
if(end+range>=array.length-1){
end = array.length - 1
flag = true
}else{
end = end+range
}
MapActor ! SumPart(array.slice(start,end),partCount)
start = start+range
}
println("Actor cost:"+(System.currentTimeMillis()-startTime))
}
def main(num:Int)={
val array = randomArray(num)
val startTime = System.currentTimeMillis()
println("No-Actor result:"+array.sum/array.length)
println("No-Actor cost:"+(System.currentTimeMillis()-startTime))
}
for(i<- 1 to 20) {
actorMain(100000, taskCount)
actorMain(100000, 100)
}
for(i<- 1 to 20) {
main(100000)
main(100000)
}

20.2
编写一个程序,读取一个大型图片到BufferedImage对象中,用javax.imageio.ImangeIo.read方法。使用多个actor,每一个actor对图形的某一个条带区域进行反色处理。当所有条带都被反色后,输出结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
import scala.actors.Actor
import scala.actors.Actor._
case class InversePart(bufImage:BufferedImage, imageRGB:Array[Int], start:Int, end:Int)
case class WriteImage(result:BufferedImage, imageRGB:Array[Int])
val inputPng = new File("./pic.png")
val outPng = new File("./pic_reverse.png")
class ImageActor(var count:Int = 0) extends Actor{
override def act()={
loop{
react{
case InversePart(bufImage, imageRGB, start, end) =>
for(i <- start to end){
imageRGB(i) = imageRGB(i)^0xffffffff
}
self ! WriteImage(bufImage, imageRGB)
case WriteImage(bufImage, imageRGB) =>
count -= 1
if(count==1) {
val width = bufImage.getWidth
val height = bufImage.getHeight
val resultImage = new BufferedImage(bufImage.getWidth, bufImage.getHeight, BufferedImage.TYPE_INT_RGB)
resultImage.setRGB(0, 0, width, height, imageRGB, 0, width)
ImageIO.write(resultImage , "png", outPng)
exit()
}
}
}
}
}
def inverse = {
val bufImage = ImageIO.read(inputPng)
if (bufImage != null) {
val width = bufImage.getWidth
val height = bufImage.getHeight
val imageRGB = new Array[Int](width * height)
bufImage.getRGB(0, 0, width, height, imageRGB, 0, width)
var step = 5
var start = 0
var end = 0
var flag = false
val count = imageRGB.length / step + 1
val imageActor = new ImageActor(count)
imageActor.start()
while (!flag) {
if (end + step >= imageRGB.length) {
end = imageRGB.length - 1
flag = true
} else {
end += step
}
imageActor ! InversePart(bufImage, imageRGB, start, end)
start += step
}
}
}
inverse

20.3
编写一个程序,对给定目录下所有子目录的所有文件中匹配某个给定的正则表达式的单词进行计数。对每一个文件各采用一个actor,另外再加上一个actor用来遍历所有子目录,还有一个actor将结果汇总到一起。

20.4
修改前一个练习的程序,显示所有匹配的单词。

20.5
修改前一个练习的程序,显示所有匹配的单词,每一个都带有一个包含它的文件的列表。

20.6
编写一个程序,构造100个actor,这些actor使用while(true)/receive循环,当接收到‘Hello消息时,调用println(Thread.currentThread),同时构造另外100个actor,他们做同样的事,不过采用loop/react。将它们全部启动,给它们全部都发送一个消息。第一种actor占用了多少线程,第二种actor占用了多少线程?

20.7
给练习3的程序添加一个监管actor,监控读取文件的actor并记录任何因IOException退出的actor。尝试通过移除那些计划要被处理的文件的方式触发IOException。

20.8
展示一个基于actor的程序是如何在发送同步消息时引发死锁的。

20.9
做出一个针对练习3的程序的有问题的实现,在这个实现当中,actor将更新一个共享的计数器。你能展现出程序运行是错误的吗?

20.10
重写练习1的程序,使用消息通道来进行通信。


参考:
《快学Scala》:http://book.douban.com/subject/19971952/

(转载本站文章请注明作者和出处 Vernon Zheng(郑雪峰) – vernonzheng.com ,请勿用于任何商业用途)