Tất cả các diễn viên về cơ bản là các chuỗi được thực thi bởi một người lên lịch dưới mui xe. Trình lập lịch biểu tạo một nhóm luồng để thực thi các tác nhân gần như ràng buộc với số lõi của bạn. Điều này có nghĩa rằng bạn chỉ có thể tạo ra một diễn viên mỗi công việc bạn cần phải thực hiện và để lại phần còn lại cho Scala:
for(i <- 1 to 20) {
actor {
print(i);
Thread.sleep(1000);
}
}
Những bất lợi ở đây là tùy thuộc vào số nhiệm vụ, chi phí của việc tạo ra một chủ đề cho mỗi công việc có thể khá đắt vì các chủ đề không quá rẻ trong Java.
Một cách đơn giản để tạo ra một hồ bơi bị chặn của các diễn viên người lao động và sau đó phân phối các nhiệm vụ đối với họ thông qua tin nhắn sẽ là một cái gì đó như:
import scala.actors.Actor._
val numWorkers = 4
val pool = (1 to numWorkers).map { i =>
actor {
loop {
react {
case x: String => println(x)
}
}
}
}
for(i <- 1 to 20) {
val r = (new util.Random).nextInt(numWorkers)
pool(r) ! "task "+i
}
Lý do chúng tôi muốn tạo nhiều diễn viên là do một quá trình diễn viên duy nhất chỉ có một thông điệp (tức là nhiệm vụ) tại một thời điểm để có được tính song song cho các nhiệm vụ của bạn, bạn cần phải tạo nhiều.
Lưu ý phụ: trình lên lịch mặc định trở nên đặc biệt quan trọng khi nói đến các tác vụ ràng buộc I/O, vì bạn chắc chắn sẽ muốn thay đổi kích thước của nhóm luồng trong trường hợp đó. Hai bài đăng trên blog tốt đi sâu vào chi tiết về điều này là: Explore the Scheduling of Scala Actors và Scala actors thread pool pitfall.
Với điều đó đã nói, Akka là khung công tác cung cấp công cụ cho quy trình công việc nâng cao hơn với diễn viên và đó là những gì tôi sẽ sử dụng trong bất kỳ ứng dụng thực tế nào. Đây là một cân bằng tải (chứ không phải là ngẫu nhiên) nhiệm vụ thi hành di chúc:
import akka.actor.Actor
import Actor._
import akka.routing.{LoadBalancer, CyclicIterator}
class TaskHandler extends Actor {
def receive = {
case t: Task =>
// some computationally expensive thing
t.execute
case _ => println("default case is required in Akka...")
}
}
class TaskRouter(numWorkers: Int) extends Actor with LoadBalancer {
val workerPool = Vector.fill(numWorkers)(actorOf[TaskHandler].start())
val seq = new CyclicIterator(workerPool)
}
val router = actorOf(new TaskRouter(4)).start()
for(i <- 1 to 20) {
router ! Task(..)
}
Bạn có thể có các loại khác nhau của Load Balancing (CyclicIterator là phân phối round-robin), vì vậy bạn có thể kiểm tra các tài liệu here để biết thêm.
Nguồn
2011-06-24 16:25:27
Bạn đã thử diễn viên Scala hoặc bộ sưu tập song song chưa? Họ có thể phân phối khối lượng công việc trên các CPU khác nhau. Nếu bạn cần kiểm soát nhiều hơn, bạn có thể xem Akka. – Fabian