การเขียน โปรแกรมพร้อมกัน เป็นเรื่องยาก การต้องจัดการกับเธรดการล็อกเงื่อนไขการแข่งขันและอื่น ๆ มีโอกาสเกิดข้อผิดพลาดสูงและอาจนำไปสู่รหัสที่ยากต่อการอ่านทดสอบและบำรุงรักษา
หลายคนจึงชอบที่จะหลีกเลี่ยงการอ่านแบบมัลติเธรดโดยสิ้นเชิง แต่พวกเขาใช้กระบวนการแบบเธรดเดียวโดยอาศัยบริการภายนอก (เช่นฐานข้อมูลคิว ฯลฯ ) เพื่อจัดการการดำเนินการพร้อมกันหรือแบบอะซิงโครนัสที่จำเป็น แม้ว่าแนวทางนี้จะเป็นทางเลือกที่ถูกต้องในบางกรณี แต่ก็มีหลายสถานการณ์ที่ไม่ใช่ทางเลือกที่เป็นไปได้ ระบบเรียลไทม์จำนวนมากเช่นแอปพลิเคชันการซื้อขายหรือการธนาคารหรือเกมแบบเรียลไทม์ไม่ต้องรอให้กระบวนการเธรดชุดเดียวเสร็จสมบูรณ์ (พวกเขาต้องการคำตอบเดี๋ยวนี้!) ระบบอื่น ๆ มีการคำนวณหรือใช้ทรัพยากรมากจนอาจต้องใช้เวลามากเกินไป (หลายชั่วโมงหรือหลายวันในบางกรณี) ในการทำงานโดยไม่ต้องนำการขนานเข้ากับโค้ด
วิธีการแบบเธรดเดียวที่ค่อนข้างใช้กันทั่วไป (ใช้กันอย่างแพร่หลายใน โหนด js โลกเป็นต้น) คือการใช้กระบวนทัศน์ที่อิงตามเหตุการณ์และไม่ปิดกั้น แม้ว่าสิ่งนี้จะช่วยเพิ่มประสิทธิภาพโดยหลีกเลี่ยงการสลับบริบทการล็อกและการบล็อก แต่ก็ยังไม่ได้แก้ไขปัญหาของการใช้โปรเซสเซอร์หลายตัวพร้อมกัน (การดำเนินการดังกล่าวจะต้องมีการเปิดใช้งานและการประสานงานระหว่างกระบวนการอิสระหลาย ๆ กระบวนการ)
ทำความเข้าใจรหัส c ++
นั่นหมายความว่าคุณไม่มีทางเลือกอื่นนอกจากต้องเดินทางลึกเข้าไปในส่วนลึกของเธรดล็อคและเงื่อนไขการแข่งขันเพื่อสร้างแอปพลิเคชันพร้อมกันหรือไม่?
ขอบคุณกรอบ Akka คำตอบคือไม่ บทช่วยสอนนี้แนะนำตัวอย่างของ Akka และสำรวจวิธีที่อำนวยความสะดวกและลดความยุ่งยากในการใช้งานแอปพลิเคชันแบบกระจายพร้อมกัน
Akka เป็นชุดเครื่องมือและรันไทม์สำหรับการสร้างแอปพลิเคชั่นที่รองรับการทำงานพร้อมกันกระจายและทนต่อข้อผิดพลาดบน JVM Akka เขียนใน บันได โดยมีการผูกภาษาสำหรับทั้ง Scala และ Java
แนวทางของ Akka ในการจัดการการทำงานพร้อมกันนั้นขึ้นอยู่กับ นักแสดงรุ่น . ในระบบที่อิงตามนักแสดงทุกอย่างคือนักแสดงในลักษณะเดียวกับที่ทุกอย่างเป็นวัตถุในการออกแบบเชิงวัตถุ แม้ว่าความแตกต่างที่สำคัญ - เกี่ยวข้องกับการสนทนาของเราโดยเฉพาะ - คือโมเดลนักแสดงได้รับการออกแบบมาโดยเฉพาะและออกแบบมาเพื่อใช้เป็นโมเดลพร้อมกันในขณะที่โมเดลเชิงวัตถุไม่ได้ โดยเฉพาะอย่างยิ่งในระบบนักแสดง Scala นักแสดงโต้ตอบและแบ่งปันข้อมูลโดยไม่ต้องมีการคาดเดาถึงลำดับ กลไกที่นักแสดงแบ่งปันข้อมูลซึ่งกันและกันและทำงานซึ่งกันและกันคือการส่งผ่านข้อความ
ความซับซ้อนทั้งหมดของการสร้างและกำหนดเวลาเธรดการรับและการส่งข้อความและการจัดการเงื่อนไขการแข่งขันและการซิงโครไนซ์จะถูกส่งไปยังกรอบงานเพื่อจัดการอย่างโปร่งใสAkka สร้างเลเยอร์ระหว่างนักแสดงและระบบพื้นฐานเพื่อให้นักแสดงต้องประมวลผลข้อความ ความซับซ้อนทั้งหมดของการสร้างและกำหนดเวลาเธรดการรับและการส่งข้อความและการจัดการเงื่อนไขการแข่งขันและการซิงโครไนซ์จะถูกส่งไปยังกรอบงานเพื่อจัดการอย่างโปร่งใส
Akka ปฏิบัติตามไฟล์ แถลงการณ์ปฏิกิริยา . แอ็พพลิเคชันแบบตอบสนองมีเป้าหมายที่การแทนที่แอ็พพลิเคชันแบบมัลติเธรดแบบดั้งเดิมด้วยสถาปัตยกรรมที่ตรงตามข้อกำหนดต่อไปนี้อย่างน้อยหนึ่งข้อ:
โดยพื้นฐานแล้วนักแสดงไม่ได้เป็นอะไรมากไปกว่าวัตถุที่รับข้อความและดำเนินการเพื่อจัดการกับพวกเขา ข้อความนี้แยกออกจากแหล่งที่มาของข้อความและความรับผิดชอบเพียงอย่างเดียวคือการรับรู้ประเภทของข้อความที่ได้รับอย่างเหมาะสมและดำเนินการตามนั้น
เมื่อได้รับข้อความนักแสดงอาจดำเนินการอย่างน้อยหนึ่งอย่างต่อไปนี้:
หรืออีกวิธีหนึ่งนักแสดงอาจเลือกที่จะเพิกเฉยต่อข้อความทั้งหมด (กล่าวคืออาจเลือกที่จะเพิกเฉย) หากเห็นว่าเหมาะสมที่จะทำเช่นนั้น
ในการใช้นักแสดงจำเป็นต้องขยาย akka.actor ลักษณะของนักแสดงและใช้วิธีการรับ ระบบจะเรียกใช้วิธีการรับของนักแสดง (โดย Akka) เมื่อมีการส่งข้อความถึงนักแสดงคนนั้น การใช้งานโดยทั่วไปประกอบด้วยการจับคู่รูปแบบดังที่แสดงในตัวอย่าง Akka ต่อไปนี้เพื่อระบุประเภทข้อความและตอบสนองตามนั้น:
import akka.actor.Actor import akka.actor.Props import akka.event.Logging class MyActor extends Actor { def receive = { case value: String => doSomething(value) case _ => println('received unknown message') } }
การจับคู่รูปแบบเป็นเทคนิคที่ค่อนข้างหรูหราในการจัดการข้อความซึ่งมีแนวโน้มที่จะสร้างโค้ดที่ 'สะอาด' และง่ายต่อการนำทางมากกว่าการใช้งานแบบเทียบเคียงตามการเรียกกลับ พิจารณาตัวอย่างเช่นการดำเนินการตามคำขอ / การตอบกลับ HTTP ที่เรียบง่าย
ก่อนอื่นให้นำสิ่งนี้ไปใช้โดยใช้กระบวนทัศน์แบบเรียกกลับใน JavaScript:
route(url, function(request){ var query = buildQuery(request); dbCall(query, function(dbResponse){ var wsRequest = buildWebServiceRequest(dbResponse); wsCall(wsRequest, function(wsResponse) { sendReply(wsResponse); }); }); });
ตอนนี้เรามาเปรียบเทียบสิ่งนี้กับการใช้งานตามรูปแบบ:
msg match { case HttpRequest(request) => { val query = buildQuery(request) dbCall(query) } case DbResponse(dbResponse) => { var wsRequest = buildWebServiceRequest(dbResponse); wsCall(dbResponse) } case WsResponse(wsResponse) => sendReply(wsResponse) }
แม้ว่าโค้ด JavaScript แบบเรียกกลับจะมีขนาดกะทัดรัด แต่ก็ยากที่จะอ่านและนำทาง ในการเปรียบเทียบรหัสตามการจับคู่รูปแบบทำให้เห็นได้ชัดขึ้นทันทีว่ากรณีใดบ้างที่กำลังพิจารณาและวิธีจัดการแต่ละกรณี
การแก้ปัญหาที่ซับซ้อนและแยกเป็นปัญหาย่อย ๆ ซ้ำ ๆ เป็นเทคนิคการแก้ปัญหาเสียงโดยทั่วไป แนวทางนี้สามารถเป็นประโยชน์อย่างยิ่งในวิทยาการคอมพิวเตอร์ (สอดคล้องกับ หลักการความรับผิดชอบเดียว ) เนื่องจากมีแนวโน้มที่จะให้รหัสที่สะอาดและเป็นโมดูลาร์โดยมีความซ้ำซ้อนเพียงเล็กน้อยหรือไม่มีเลยซึ่งค่อนข้างง่ายต่อการบำรุงรักษา
ในการออกแบบตามนักแสดงการใช้เทคนิคนี้ช่วยให้องค์กรเชิงตรรกะของนักแสดงกลายเป็นโครงสร้างลำดับชั้นที่เรียกว่า ระบบนักแสดง . ระบบนักแสดงจัดเตรียมโครงสร้างพื้นฐานที่นักแสดงโต้ตอบซึ่งกันและกัน
ใน Akka วิธีเดียวที่จะสื่อสารกับนักแสดงคือ ActorRef
อัน ActorRef
แสดงถึงการอ้างอิงถึงนักแสดงที่กีดกันวัตถุอื่น ๆ จากการเข้าถึงโดยตรงหรือจัดการกับภายในและสถานะของนักแสดงคนนั้น อาจมีการส่งข้อความถึงนักแสดงผ่านทาง ActorRef
โดยใช้หนึ่งในโปรโตคอลไวยากรณ์ต่อไปนี้:
!
(“ บอก”) - ส่งข้อความและส่งกลับทันที?
(“ ask”) - ส่งข้อความและส่งกลับ a อนาคต แทนคำตอบที่เป็นไปได้นักแสดงแต่ละคนมีกล่องจดหมายสำหรับส่งข้อความขาเข้า มีการใช้งานกล่องจดหมายหลายแบบให้เลือกโดยการใช้งานเริ่มต้นคือ FIFO
นักแสดงมีตัวแปรอินสแตนซ์จำนวนมากเพื่อรักษาสถานะขณะประมวลผลข้อความหลายข้อความ Akka ช่วยให้มั่นใจได้ว่าอินสแตนซ์ของนักแสดงแต่ละคนทำงานในเธรดที่มีน้ำหนักเบาของตัวเองและข้อความจะถูกประมวลผลทีละรายการ ด้วยวิธีนี้จะรักษาสถานะของนักแสดงแต่ละคนได้อย่างน่าเชื่อถือโดยที่นักพัฒนาไม่จำเป็นต้องกังวลอย่างชัดเจนเกี่ยวกับการซิงโครไนซ์หรือเงื่อนไขการแข่งขัน
นักแสดงแต่ละคนจะได้รับข้อมูลที่เป็นประโยชน์ต่อไปนี้สำหรับการปฏิบัติงานผ่าน Akka Actor API:
sender
: อัน ActorRef
ไปยังผู้ส่งข้อความที่กำลังดำเนินการcontext
: ข้อมูลและวิธีการที่เกี่ยวข้องกับบริบทที่นักแสดงกำลังทำงานอยู่ (รวมถึงวิธีการ actorOf
สำหรับการสร้างอินสแตนซ์นักแสดงใหม่)supervisionStrategy
: กำหนดกลยุทธ์ที่จะใช้สำหรับการกู้คืนจากข้อผิดพลาดself
: the ActorRef
สำหรับนักแสดงเองเพื่อช่วยรวมบทช่วยสอนเหล่านี้เข้าด้วยกันลองพิจารณาตัวอย่างง่ายๆของการนับจำนวนคำในไฟล์ข้อความ
สำหรับวัตถุประสงค์ของตัวอย่าง Akka เราจะแยกปัญหาออกเป็นสองงานย่อย กล่าวคือ (1) งาน 'เด็ก' ในการนับจำนวนคำในบรรทัดเดียวและ (2) งาน 'หลัก' ในการสรุปจำนวนคำต่อบรรทัดเพื่อให้ได้จำนวนคำทั้งหมดในไฟล์
ผู้แสดงหลักจะโหลดแต่ละบรรทัดจากไฟล์จากนั้นมอบหมายให้นักแสดงเด็กทำหน้าที่นับจำนวนคำในบรรทัดนั้น เมื่อเด็กทำเสร็จแล้วก็จะส่งข้อความกลับไปยังผู้ปกครองพร้อมผลลัพธ์ ผู้ปกครองจะได้รับข้อความที่มีจำนวนคำ (สำหรับแต่ละบรรทัด) และมีตัวนับสำหรับจำนวนคำทั้งหมดในไฟล์ทั้งหมดซึ่งจะส่งกลับไปยังผู้เรียกใช้เมื่อเสร็จสิ้น
(โปรดทราบว่าตัวอย่างโค้ดบทช่วยสอน Akka ที่ให้ไว้ด้านล่างมีไว้เพื่อการสอนเท่านั้นดังนั้นจึงไม่จำเป็นต้องเกี่ยวข้องกับเงื่อนไขขอบทั้งหมดการเพิ่มประสิทธิภาพการทำงานและอื่น ๆ นอกจากนี้ตัวอย่างโค้ดเวอร์ชันที่รวบรวมได้ทั้งหมดที่แสดงด้านล่างมีอยู่ใน นี้ สาระสำคัญ .)
ก่อนอื่นมาดูตัวอย่างการใช้งานเด็ก StringCounterActor
ชั้น:
case class ProcessStringMsg(string: String) case class StringProcessedMsg(words: Integer) class StringCounterActor extends Actor { def receive = { case ProcessStringMsg(string) => { val wordsInLine = string.split(' ').length sender ! StringProcessedMsg(wordsInLine) } case _ => println('Error: message not recognized') } }
นักแสดงคนนี้มีภารกิจที่ง่ายมาก: บริโภค ProcessStringMsg
ข้อความ (ประกอบด้วยบรรทัดข้อความ) นับจำนวนคำในบรรทัดที่ระบุและส่งคืนผลลัพธ์ไปยังผู้ส่งผ่านทาง StringProcessedMsg
ข้อความ. โปรดทราบว่าเราได้นำคลาสของเราไปใช้กับ !
(“ บอก”) วิธีการส่ง StringProcessedMsg
ข้อความ (เช่นเพื่อส่งข้อความและส่งกลับทันที)
ตกลงตอนนี้เรามาสนใจผู้ปกครองกันเถอะ WordCounterActor
ชั้น:
ทำงานหมายเลขบัตรเครดิต 2017 กับเงิน
1. case class StartProcessFileMsg() 2. 3. class WordCounterActor(filename: String) extends Actor { 4. 5. private var running = false 6. private var totalLines = 0 7. private var linesProcessed = 0 8. private var result = 0 9. private var fileSender: Option[ActorRef] = None 10. 11. def receive = { 12. case StartProcessFileMsg() => { 13. if (running) { 14. // println just used for example purposes; 15. // Akka logger should be used instead 16. println('Warning: duplicate start message received') 17. } else { 18. running = true 19. fileSender = Some(sender) // save reference to process invoker 20. import scala.io.Source._ 21. fromFile(filename).getLines.foreach { line => 22. context.actorOf(Props[StringCounterActor]) ! ProcessStringMsg(line) 23. totalLines += 1 24. } 25. } 26. } 27. case StringProcessedMsg(words) => { 28. result += words 29. linesProcessed += 1 30. if (linesProcessed == totalLines) { 31. fileSender.map(_ ! result) // provide result to process invoker 32. } 33. } 34. case _ => println('message not recognized!') 35. } 36. }
มีหลายสิ่งเกิดขึ้นที่นี่เรามาดูรายละเอียดแต่ละข้อกันดีกว่า (โปรดทราบว่าหมายเลขบรรทัดที่อ้างถึงในการสนทนาที่ตามมาเป็นไปตามตัวอย่างโค้ดด้านบน) ...
ขั้นแรกให้สังเกตว่าชื่อของไฟล์ที่จะประมวลผลถูกส่งไปยัง WordCounterActor
ตัวสร้าง (บรรทัดที่ 3) สิ่งนี้บ่งชี้ว่านักแสดงจะถูกใช้เพื่อประมวลผลไฟล์เดียวเท่านั้น นอกจากนี้ยังช่วยลดความซับซ้อนของงานการเข้ารหัสสำหรับนักพัฒนาโดยหลีกเลี่ยงความจำเป็นในการรีเซ็ตตัวแปรสถานะ (running
, totalLines
, linesProcessed
และ result
) เมื่องานเสร็จสิ้น เนื่องจากอินสแตนซ์ถูกใช้เพียงครั้งเดียว (กล่าวคือเพื่อประมวลผลไฟล์เดียว) จากนั้นจึงทิ้ง
ถัดไปสังเกตว่า WordCounterActor
จัดการข้อความสองประเภท:
StartProcessFileMsg
(บรรทัดที่ 12)WordCounterActor
.WordCounterActor
ก่อนอื่นให้ตรวจสอบว่าไม่ได้รับคำขอซ้ำซ้อนWordCounterActor
สร้างคำเตือนและไม่มีอะไรทำอีกแล้ว (บรรทัดที่ 16)WordCounterActor
จัดเก็บข้อมูลอ้างอิงถึงผู้ส่งใน fileSender
ตัวแปรอินสแตนซ์ (โปรดทราบว่านี่คือ Option[ActorRef]
แทนที่จะเป็น Option[Actor]
- ดูบรรทัดที่ 9) นี้ ActorRef
จำเป็นเพื่อเข้าถึงและตอบสนองในภายหลังเมื่อประมวลผลขั้นสุดท้าย StringProcessedMsg
(ซึ่งได้รับจาก StringCounterActor
เด็กตามที่อธิบายไว้ด้านล่าง)WordCounterActor
จากนั้นอ่านไฟล์และเมื่อโหลดแต่ละบรรทัดในไฟล์ a StringCounterActor
เด็กถูกสร้างขึ้นและข้อความที่มีบรรทัดที่จะประมวลผลจะถูกส่งผ่านไป (บรรทัดที่ 21-24)StringProcessedMsg
(บรรทัดที่ 27)StringCounterActor
เมื่อประมวลผลบรรทัดที่กำหนดให้เสร็จสิ้นWordCounterActor
เพิ่มตัวนับบรรทัดสำหรับไฟล์และหากทุกบรรทัดในไฟล์ได้รับการประมวลผล (เช่นเมื่อ totalLines
และ linesProcessed
เท่ากัน) จะส่งผลลัพธ์สุดท้ายไปยังต้นฉบับ fileSender
(บรรทัดที่ 28-31)สังเกตอีกครั้งว่าใน Akka กลไกเดียวสำหรับการสื่อสารระหว่างนักแสดงคือการส่งข้อความ ข้อความเป็นสิ่งเดียวที่นักแสดงแบ่งปันและเนื่องจากนักแสดงสามารถเข้าถึงข้อความเดียวกันได้ในเวลาเดียวกันสิ่งสำคัญคือต้องไม่เปลี่ยนรูปเพื่อหลีกเลี่ยงสภาพการแข่งขันและพฤติกรรมที่ไม่คาดคิด
ทำไมกรีซถึงเป็นหนี้คลาสเคส ใน Scala เป็นคลาสปกติที่มีกลไกการสลายตัวแบบวนซ้ำผ่านการจับคู่รูปแบบ
ดังนั้นจึงเป็นเรื่องปกติที่จะส่งผ่านข้อความในรูปแบบของคลาสเคสเนื่องจากไม่เปลี่ยนรูปตามค่าเริ่มต้นและเนื่องจากการรวมเข้ากับการจับคู่รูปแบบได้อย่างราบรื่น
มาสรุปตัวอย่างกับตัวอย่างโค้ดเพื่อเรียกใช้แอปทั้งหมด
object Sample extends App { import akka.util.Timeout import scala.concurrent.duration._ import akka.pattern.ask import akka.dispatch.ExecutionContexts._ implicit val ec = global override def main(args: Array[String]) { val system = ActorSystem('System') val actor = system.actorOf(Props(new WordCounterActor(args(0)))) implicit val timeout = Timeout(25 seconds) val future = actor ? StartProcessFileMsg() future.map { result => println('Total number of words ' + result) system.shutdown } } }
ในการเขียนโปรแกรมพร้อมกัน 'อนาคต' เป็นวัตถุตัวยึดสำหรับผลลัพธ์ที่ยังไม่ทราบแน่ชัดสังเกตว่าเวลานี้ ?
ใช้วิธีการส่งข้อความ ด้วยวิธีนี้ผู้โทรสามารถใช้การส่งคืน อนาคต เพื่อพิมพ์ผลลัพธ์สุดท้ายเมื่อพร้อมใช้งานและออกจากโปรแกรมโดยปิด ActorSystem
ในระบบนักแสดงนักแสดงแต่ละคนเป็นผู้ดูแลลูก ๆ หากนักแสดงไม่สามารถจัดการกับข้อความได้นักแสดงจะระงับตัวเองและลูก ๆ ทั้งหมดและส่งข้อความโดยปกติจะอยู่ในรูปแบบของการยกเว้นไปยังหัวหน้างาน
ใน Akka กลยุทธ์ของหัวหน้างานเป็นกลไกหลักและตรงไปตรงมาในการกำหนดพฤติกรรมการยอมรับข้อผิดพลาดของระบบของคุณใน Akka วิธีที่หัวหน้างานตอบสนองและจัดการกับข้อยกเว้นที่ซึมผ่านมาจากเด็ก ๆ เรียกว่ากลยุทธ์ของหัวหน้างาน กลยุทธ์ของหัวหน้างาน เป็นกลไกหลักและตรงไปตรงมาที่คุณกำหนดพฤติกรรมการยอมรับความผิดพลาดของระบบของคุณ
เมื่อข้อความที่แสดงถึงความล้มเหลวไปถึงหัวหน้างานอาจดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้:
ยิ่งไปกว่านั้นนักแสดงสามารถตัดสินใจที่จะใช้การกระทำกับเด็กที่ล้มเหลวหรือพี่น้องได้เช่นกัน มีสองกลยุทธ์ที่กำหนดไว้ล่วงหน้าสำหรับสิ่งนี้:
OneForOneStrategy
: ใช้การดำเนินการที่ระบุกับเด็กที่ล้มเหลวเท่านั้นAllForOneStrategy
: ใช้การกระทำที่ระบุกับลูก ๆ ทั้งหมดนี่คือตัวอย่างง่ายๆโดยใช้ OneForOneStrategy
:
import akka.actor.OneForOneStrategy import akka.actor.SupervisorStrategy._ import scala.concurrent.duration._ override val supervisorStrategy = OneForOneStrategy() { case _: ArithmeticException => Resume case _: NullPointerException => Restart case _: IllegalArgumentException => Stop case _: Exception => Escalate }
หากไม่มีการระบุกลยุทธ์จะใช้กลยุทธ์เริ่มต้นต่อไปนี้:
การใช้กลยุทธ์เริ่มต้นนี้โดย Akka มีดังต่อไปนี้:
final val defaultStrategy: SupervisorStrategy = { def defaultDecider: Decider = { case _: ActorInitializationException ⇒ Stop case _: ActorKilledException ⇒ Stop case _: Exception ⇒ Restart } OneForOneStrategy()(defaultDecider) }
Akka อนุญาตให้ใช้ กลยุทธ์ของหัวหน้างานที่กำหนดเอง แต่ตามที่เอกสาร Akka เตือนโปรดดำเนินการด้วยความระมัดระวังเนื่องจากการใช้งานที่ไม่ถูกต้องอาจนำไปสู่ปัญหาเช่นระบบนักแสดงที่ถูกบล็อก (เช่นนักแสดงที่ถูกระงับถาวร)
สถาปัตยกรรม Akka รองรับ ความโปร่งใสของสถานที่ ทำให้นักแสดงไม่เชื่อเรื่องพระเจ้าโดยสิ้นเชิงว่าข้อความที่พวกเขาได้รับมานั้นมาจากที่ใด ผู้ส่งข้อความอาจอยู่ใน JVM เดียวกันกับผู้แสดงหรือใน JVM แยกต่างหาก (รันบนโหนดเดียวกันหรือโหนดอื่น) Akka ช่วยให้แต่ละกรณีสามารถจัดการในลักษณะที่โปร่งใสสำหรับนักแสดง (และดังนั้นผู้พัฒนา) ข้อแม้เดียวคือข้อความที่ส่งข้ามหลายโหนดจะต้องต่ออนุกรมกันได้
สถาปัตยกรรม Akka รองรับความโปร่งใสของสถานที่ทำให้นักแสดงไม่เชื่อเรื่องพระเจ้าอย่างสิ้นเชิงว่าข้อความที่ได้รับมาจากที่ใดระบบ Actor ได้รับการออกแบบให้ทำงานในสภาพแวดล้อมแบบกระจายโดยไม่ต้องใช้รหัสพิเศษใด ๆ Akka ต้องการเฉพาะไฟล์คอนฟิกูเรชัน (application.conf
) ที่ระบุโหนดที่จะส่งข้อความถึง ตัวอย่างง่ายๆของไฟล์การกำหนดค่ามีดังนี้
akka { actor { provider = 'akka.remote.RemoteActorRefProvider' } remote { transport = 'akka.remote.netty.NettyRemoteTransport' netty { hostname = '127.0.0.1' port = 2552 } } }
เราได้เห็นว่ากรอบงาน Akka ช่วยให้เกิดการทำงานพร้อมกันและประสิทธิภาพสูงได้อย่างไร อย่างไรก็ตามตามที่บทช่วยสอนนี้ชี้ให้เห็นมีบางประเด็นที่ควรคำนึงถึงเมื่อออกแบบและใช้ระบบของคุณเพื่อใช้ประโยชน์จากพลังของ Akka อย่างเต็มที่:
นักแสดงควรจัดการกับเหตุการณ์ต่างๆ (เช่นข้อความประมวลผล) แบบอะซิงโครนัสและไม่ควรปิดกั้นมิฉะนั้นการสลับบริบทจะเกิดขึ้นซึ่งอาจส่งผลเสียต่อประสิทธิภาพ โดยเฉพาะอย่างยิ่งควรดำเนินการบล็อก (IO ฯลฯ ) ในอนาคตเพื่อไม่ให้ปิดกั้นนักแสดง เช่น:
case evt => blockingCall() // BAD case evt => Future { blockingCall() // GOOD }
Akka เขียนใน บันได ลดความซับซ้อนและอำนวยความสะดวกในการพัฒนาแอปพลิเคชั่นที่มีการกระจายและทนต่อความผิดพลาดสูงพร้อมกันโดยซ่อนความซับซ้อนจากผู้พัฒนา การทำความยุติธรรมอย่างเต็มที่ของ Akka จะต้องใช้มากกว่าแบบฝึกหัดเดียวนี้ แต่หวังว่าบทนำและตัวอย่างนี้จะน่าดึงดูดพอที่จะทำให้คุณอยากอ่านเพิ่มเติม
Amazon, VMWare และ CSC เป็นเพียงตัวอย่างของ บริษัท ชั้นนำที่ใช้งาน Akka อย่างจริงจัง เยี่ยมชม เว็บไซต์ Akka อย่างเป็นทางการ เพื่อเรียนรู้เพิ่มเติมและสำรวจว่า Akka อาจเป็นคำตอบที่เหมาะสมสำหรับโครงการของคุณหรือไม่