0Pricing
Scala for Backend Engineering & Functional Programming · บทเรียน

การเพิ่มประสิทธิภาพโค้ดพร้อมกัน

เรียนรู้เทคนิคขั้นสูงเพื่อเพิ่มประสิทธิภาพแอปพลิเคชัน Scala ที่ทำงานพร้อมกัน รวมถึงการปรับแต่งกลุ่มเธรดและการหลีกเลี่ยงการแย่งใช้ทรัพยากร

การเพิ่มประสิทธิภาพโค้ดพร้อมกัน เป็นบทเรียน Scala for Backend Engineering & Functional Programming ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Scala for Backend Engineering & Functional Programming และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 3 บทเรียน

เหตุใดจึงต้องปรับปรุงโค้ดที่ทำงานพร้อมกัน

การปรับปรุงโค้ด Scala ที่ทำงานพร้อมกันเป็นสิ่งสำคัญต่อการสร้างแอปพลิเคชันที่มีประสิทธิภาพสูงและรองรับการขยายขนาดได้ดี เป้าหมายคือทำให้โปรแกรมทำงานเร็วขึ้นและจัดการงานได้มากขึ้นพร้อมกัน

  • ปริมาณงาน: สามารถดำเนินการได้กี่รายการต่อหน่วยเวลา
  • เวลาแฝง: การดำเนินการหนึ่งรายการใช้เวลานานเท่าใด
  • การใช้ทรัพยากร: แกน CPU และหน่วยความจำถูกใช้อย่างมีประสิทธิภาพหรือไม่

โค้ดที่ทำงานพร้อมกันแต่ปรับปรุงได้ไม่ดีอาจทำให้เกิดคอขวด การหยุดชะงัก และการใช้ทรัพยากรอย่างไม่มีประสิทธิภาพ จนลบล้างประโยชน์ของการทำงานพร้อมกัน

พูลเธรดทำงานอย่างไร

พูลเธรด คือกลุ่มเธรดผู้ปฏิบัติงานที่เตรียมไว้ล่วงหน้าและนำกลับมาใช้ซ้ำเพื่อดำเนินงาน แทนที่จะสร้างเธรดใหม่สำหรับแต่ละงาน ซึ่งมีค่าใช้จ่ายสูง งานต่าง ๆ จะถูกส่งไปยังพูล

วิธีนี้ช่วยลดค่าใช้จ่ายในการสร้างและทำลายเธรด เพิ่มการตอบสนอง และช่วยจัดการจำนวนเธรดที่ทำงานอยู่เพื่อป้องกันการใช้ทรัพยากรมากเกินไป

กำหนดค่าพูลส่วนกลางของ Scala

ใน Scala การดำเนินการแบบอะซิงโครนัสมักใช้ ExecutionContext โดยค่าเริ่มต้น แอปพลิเคชัน Scala จะใช้ ExecutionContext ส่วนกลาง ซึ่งโดยทั่วไปคือ ForkJoinPool

คุณสามารถปรับแต่งพูลเริ่มต้นนี้ได้โดยกำหนดคุณสมบัติของระบบ หรือโดยทั่วไปกว่านั้นคือกำหนดการตั้งค่าดิสแพตเชอร์ใน application.conf โดยเฉพาะในแอปพลิเคชันที่ใช้ Akka วิธีนี้ช่วยให้คุณควบคุมจำนวนเธรด พฤติกรรมการขโมยงาน และขนาดคิวได้

การตั้งค่าที่มักปรับคือ parallelism-factor เพื่อปรับขนาดพูลให้สัมพันธ์กับจำนวนแกน CPU ที่พร้อมใช้งาน

สร้าง ExecutionContext แบบกำหนดเอง

แม้ ExecutionContext ส่วนกลางจะสะดวก แต่บ่อยครั้งการสร้างพูลเธรดแบบกำหนดเองสำหรับงานแต่ละประเภทจะเหมาะสมกว่า ตัวอย่างเช่น ใช้พูลขนาดเล็กสำหรับงานที่ใช้ CPU และพูลขนาดใหญ่กว่าสำหรับงานที่ใช้การรับส่งข้อมูลเข้าออก

วิธีนี้ช่วยป้องกันไม่ให้การดำเนินการรับส่งข้อมูลที่ช้าขัดขวางงานที่ใช้ CPU และช่วยให้ระบบตอบสนองโดยรวมดีขึ้น ต่อไปนี้คือวิธีสร้าง ExecutionContext แบบกำหนดเองอย่างง่าย:

import java.util.concurrent.{Executors, ExecutorService}
import scala.concurrent.ExecutionContext

object CustomPoolExample {
  def main(args: Array[String]): Unit = {
    // Create a fixed thread pool with 4 threads
    val customExecutor: ExecutorService =
      Executors.newFixedThreadPool(4)

    // Wrap it in a Scala ExecutionContext
    implicit val customEC: ExecutionContext =
      ExecutionContext.fromExecutor(customExecutor)

    println("Custom ExecutionContext created.")

    // Don't forget to shut down the executor!
    customExecutor.shutdown()
  }
}

ลดการแย่งชิงทรัพยากร

การแย่งชิง เกิดขึ้นเมื่อมีหลายเธรดพยายามเข้าถึงทรัพยากรที่ใช้ร่วมกัน เช่น ตัวแปร โครงสร้างข้อมูล หรือการเชื่อมต่อฐานข้อมูล ในเวลาเดียวกัน และมีเธรดอย่างน้อยหนึ่งเธรดต้องรอ

การรอนี้ทำให้เกิดความล่าช้าและค่าใช้จ่ายเพิ่มเติม เนื่องจากเธรดต้องแข่งขันกันใช้ล็อกและรอบการทำงานของ CPU การแย่งชิงที่สูงอาจทำให้ประสิทธิภาพของแอปพลิเคชันที่ทำงานพร้อมกันลดลงอย่างมาก แม้จะมีแกน CPU ให้ใช้งานหลายแกน

กลยุทธ์ในการลดการแย่งชิงเป็นกุญแจสำคัญในการดึงศักยภาพของการทำงานแบบขนานออกมาอย่างแท้จริง

การล็อกแบบละเอียด

แทนที่จะใช้ล็อกขนาดหยาบเพียงตัวเดียวเพื่อป้องกันออบเจ็กต์ทั้งหมดหรือบล็อกโค้ดขนาดใหญ่ การล็อกแบบละเอียด จะใช้ล็อกขนาดเล็กและเฉพาะเจาะจงมากขึ้น เพื่อป้องกันเฉพาะส่วนของข้อมูลที่กำลังถูกแก้ไขจริง ๆ

วิธีนี้ทำให้เธรดต่าง ๆ สามารถเข้าถึงส่วนต่าง ๆ ของออบเจ็กต์พร้อมกันได้ จึงลดการแย่งชิงลงอย่างมาก อย่างไรก็ตาม วิธีนี้เพิ่มความซับซ้อนและความเสี่ยงที่จะเกิดการหยุดชะงัก หากจัดการไม่รอบคอบ

class Counter {
  private var value = 0
  private val lock = new Object() // A specific lock for 'value'

  def increment(): Unit = lock.synchronized {
    value += 1
  }

  def get(): Int = lock.synchronized {
    value
  }
}

object FineGrainedLocking {
  def main(args: Array[String]): Unit = {
    val counter = new Counter()
    println(s"Initial counter value: ${counter.get()}")
    counter.increment()
    println(s"Incremented value: ${counter.get()}")
  }
}

การดำเนินการแบบอะตอมิกเพื่อประสิทธิภาพ

โครงสร้างข้อมูลที่ไม่ใช้ล็อก ใช้การดำเนินการระดับต่ำแบบอะตอมิก เช่น Compare-And-Swap หรือ CAS เพื่ออัปเดตตัวแปรที่ใช้ร่วมกันโดยไม่ต้องใช้ล็อกโดยตรง วิธีนี้ช่วยหลีกเลี่ยงค่าใช้จ่ายและการแย่งชิงที่อาจเกิดจากกลไกการล็อกแบบดั้งเดิม

Scala ใช้แพ็กเกจ java.util.concurrent.atomic ของ Java สำหรับงานนี้ คลาสต่าง ๆ เช่น AtomicInteger, AtomicLong และ AtomicReference มีการอัปเดตแบบอะตอมิก จึงเหมาะสำหรับสถานการณ์ที่มีการแย่งชิงสูง

import java.util.concurrent.atomic.AtomicInteger

object AtomicCounterExample {
  def main(args: Array[String]): Unit = {
    val atomicCounter = new AtomicInteger(0)

    // Increment the counter atomically
    atomicCounter.incrementAndGet()
    println(s"Atomic counter after increment: ${atomicCounter.get()}")

    // Another atomic operation: add 5
    atomicCounter.addAndGet(5)
    println(s"Atomic counter after adding 5: ${atomicCounter.get()}")
  }
}

วัดประสิทธิภาพอย่างแม่นยำ

หากต้องการทราบอย่างแท้จริงว่าการปรับปรุงโค้ดที่ทำงานพร้อมกันได้ผลหรือไม่ คุณต้องวัดผลอย่างแม่นยำ การจับเวลาอย่างง่ายด้วย System.nanoTime() มักไม่เพียงพอสำหรับโค้ดที่ทำงานพร้อมกัน เนื่องจากการปรับปรุงของ JVM ช่วงวอร์มอัป และการสลับบริบท

เครื่องมือวัดประสิทธิภาพระดับมืออาชีพอย่าง JMH (Java Microbenchmark Harness) ได้รับการออกแบบมาเพื่อจุดประสงค์นี้ เครื่องมือจะจัดการช่วงวอร์มอัปของ JVM การกำจัดโค้ดที่ไม่มีผล และให้การวิเคราะห์ทางสถิติ ทำให้ได้ตัวชี้วัดประสิทธิภาพที่น่าเชื่อถือสำหรับอัลกอริทึมที่ทำงานพร้อมกัน

ให้มุ่งเน้นตัวชี้วัด เช่น จำนวนการดำเนินการต่อวินาที (ปริมาณงาน) และเวลาเฉลี่ยในการดำเนินการ (เวลาแฝง) ภายใต้เงื่อนไขปริมาณงานที่แตกต่างกัน

ตรวจสอบการปรับปรุงการทำงานพร้อมกัน

ข้อใดต่อไปนี้เป็นกลยุทธ์ที่มีประสิทธิภาพในการปรับปรุงแอปพลิเคชัน Scala ที่ทำงานพร้อมกันและลดการแย่งชิง

ทบทวน: ประสิทธิภาพการทำงานพร้อมกันที่ดียิ่งขึ้น

ในบทเรียนนี้ เราได้สำรวจเทคนิคขั้นสูงสำหรับการปรับปรุงแอปพลิเคชัน Scala ที่ทำงานพร้อมกัน:

  • เราได้เรียนรู้ความสำคัญของการปรับแต่งพูลเธรด ซึ่งรวมถึงการกำหนดค่า ExecutionContext เริ่มต้นของ Scala และการสร้างพูลแบบกำหนดเองสำหรับงานแต่ละประเภท
  • เราได้พูดถึงกลยุทธ์การหลีกเลี่ยงการแย่งชิง เช่น การลดความละเอียดของล็อกด้วยการล็อกแบบละเอียด
  • เราได้เห็นว่าโครงสร้างข้อมูลที่ไม่ใช้ล็อก โดยเฉพาะตัวแปรแบบอะตอมิก สามารถอัปเดตสถานะที่ใช้ร่วมกันได้อย่างมีประสิทธิภาพและมีค่าใช้จ่ายต่ำ

โปรดจำไว้ว่า ควรวัดผลกระทบจากการปรับปรุงของคุณด้วยเครื่องมือวัดประสิทธิภาพที่เหมาะสมเสมอ เพื่อให้มั่นใจว่าได้ประสิทธิภาพเพิ่มขึ้นจริง

คำถามที่พบบ่อย

บทเรียน “การเพิ่มประสิทธิภาพโค้ดพร้อมกัน” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การเพิ่มประสิทธิภาพโค้ดพร้อมกัน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Scala for Backend Engineering & Functional Programming ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 3 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การเพิ่มประสิทธิภาพโค้ดพร้อมกัน”

เรียนรู้เทคนิคขั้นสูงเพื่อเพิ่มประสิทธิภาพแอปพลิเคชัน Scala ที่ทำงานพร้อมกัน รวมถึงการปรับแต่งกลุ่มเธรดและการหลีกเลี่ยงการแย่งใช้ทรัพยากร คุณปฏิบัติ Scala for Backend Engineering & Functional Programming ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Scala for Backend Engineering & Functional Programming หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Scala for Backend Engineering & Functional Programming บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน

บทเรียน “การเพิ่มประสิทธิภาพโค้ดพร้อมกัน” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Scala for Backend Engineering & Functional Programming นี้ได้ไหม

ได้ บทเรียน Scala for Backend Engineering & Functional Programming ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การวิเคราะห์ประสิทธิภาพแอปพลิเคชัน Scala
  2. การจัดการหน่วยความจำและการปรับแต่ง GC
  3. การเพิ่มประสิทธิภาพโค้ดพร้อมกัน
← กลับไปที่ Scala for Backend Engineering & Functional Programming