Actor — คืออะไร การแยกข้อมูล และการทำงานพร้อมกัน

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-18 เวลาอ่าน: 11 นาที

Actor เป็นชนิดที่ถูกนำเสนอใน Swift 5.5+ ซึ่งแก้ปัญหาการแข่งข้อมูลในระดับภาษา ต่างจากการล็อกด้วยตนเองและคิว DispatchQueue actor จะแยกสถานะของมันโดยอัตโนมัติและซิงโครไนซ์การเข้าถึงมัน ซึ่งหมายความว่าสองเธรดไม่สามารถแก้ไขพร็อพเพอร์ตี้เดียวกันของชนิด actor พร้อมกันได้ ซึ่งช่วยกำจัดสภาวะแข่งขันโดยไม่ต้องใช้ความพยายามเพิ่มเติมจากนักพัฒนา กลไกนี้มีพื้นฐานมาจากแนวคิดของการแยก actor ซึ่งคอมไพเลอร์จะติดตามการเข้าถึงพร็อพเพอร์ตี้และเมธอดของ actor ตาม Apple, 2025 โมเดล actor เป็นส่วนพื้นฐานของระบบการทำงานพร้อมกันของ Swift

ประเด็นสำคัญ

  • Actor เป็นชนิดที่แยกสถานะของมันจากการแข่งข้อมูลโดยอัตโนมัติในระดับคอมไพเลอร์
  • การแยก รับประกันว่าเพียงหนึ่งเธรดเท่านั้นที่เข้าถึงอินสแตนซ์ของ actor ในแต่ละครั้ง
  • การเรียก เมธอดของ actor ทำงานแบบอะซิงโครนัสผ่านกลไก async/await
  • Nonisolated อนุญาตให้ปิดการแยกแบบเลือกได้สำหรับสมาชิก actor แต่ละตัว
  • Reentrancy อนุญาตให้เข้า actor ซ้ำ ป้องกันการตายแบบ

Actor ใน Swift คืออะไร?

Actor เป็นชนิดอ้างอิง คล้ายกับคลาส แต่มีการป้องกันอัตโนมัติต่อการแข่งข้อมูล มันถูกนำเสนอใน Swift 5.5 ซึ่งเป็นส่วนหนึ่งของระบบการทำงานพร้อมกันควบคู่ไปกับ async/await และ Task Actor รับประกันว่าสถานะที่เปลี่ยนแปลงได้ของมันจะไม่ถูกอ่านหรือเขียนพร้อมกันจากเธรดที่แตกต่างกันโดยไม่มีการซิงโครไนซ์ที่ชัดเจน

ไวยากรณ์การประกาศ Actor

ในการประกาศ actor ให้ใช้คำหลัก actor ตามด้วยวงเล็บปีกกาที่มีสมาชิกของมัน ในทางไวยากรณ์ actor มีลักษณะคล้ายคลาส แต่พฤติกรรมของมันแตกต่างอย่างสิ้นเชิง

swift
actor BankAccount {
    private var balance: Double
    
    init(initialBalance: Double) {
        self.balance = initialBalance
    }
    
    func deposit(amount: Double) {
        balance += amount
    }
    
    func getBalance() -> Double {
        return balance
    }
}

คอมไพเลอร์จะแยกพร็อพเพอร์ตี้และเมธอดทั้งหมดของ actor โดยอัตโนมัติเพื่อให้เข้าถึงได้เฉพาะภายใน บริบทของ actor เท่านั้น เมื่อพยายามเข้าถึง balance จากภายนอก actor คอมไพเลอร์จะสร้างข้อผิดพลาดหากการเรียกไม่ได้ถูกทำเครื่องหมายเป็น async

การแยกข้อมูลใน Actor ทำงานอย่างไร

การแยกข้อมูล เป็นแนวคิดหลักของ actor Actor รับประกันการเข้าถึงสถานะของมันแบบเอกสิทธิ์ซึ่งกันและกันผ่านกลไกของผู้ดำเนินการ actor แต่ละ actor มีผู้ดำเนินการของตัวเองที่ประมวลผลการเข้าถึงสมาชิกที่ถูกแยกทั้งหมดตามลำดับ

หลักการทำงานของการแยก

เมื่อโค้ดภายนอก actor เรียกเมธอดของมัน การเรียกจะถูกวางในคิวของ ผู้ดำเนินการ actor Actor ดำเนินการเพียงงานเดียวในแต่ละครั้ง รับประกันว่าไม่มีการแข่งกัน หากสองเธรดเรียก deposit พร้อมกัน การเรียกที่สองจะรอให้การเรียกแรกเสร็จสมบูรณ์

swift
let account = BankAccount(initialBalance: 1000.0)
// การเรียกแบบอะซิงโครนัส — จำเป็นจากภายนอก actor
await account.deposit(amount: 500.0)
let currentBalance = await account.getBalance()

ทุกการเรียกเมธอดของ actor จำเป็นต้องมี await เพราะ actor อาจกำลังยุ่งกับงานอื่น นี่ไม่ใช่บั๊ก แต่เป็นการออกแบบโดยเจตนาที่ป้องกันการแข่งกัน Swift ทำให้ getter และ setter ของพร็อพเพอร์ตี้ของ actor เป็น async โดยปริยาย ดังนั้นการอ่านพร็อพเพอร์ตี้ก็จำเป็นต้องมี await เช่นกัน

ความแตกต่างหลักระหว่าง Actor และคลาส

Actor และคลาสเป็นชนิดอ้างอิงทั้งคู่ แต่พฤติกรรมของพวกมันในสภาพแวดล้อมแบบหลายเธรดแตกต่างกันอย่างมาก คลาสไม่ให้การป้องกันอัตโนมัติใด ๆ ต่อการแข่งกัน ในขณะที่ actor ฝังมันไว้ในระดับคอมไพเลอร์ผ่านระบบชนิด

ลักษณะActorคลาส
การป้องกันการแข่งอัตโนมัติ ในระดับคอมไพเลอร์ต้องการการซิงโครไนซ์ด้วยตนเอง
การเข้าถึงพร็อพเพอร์ตี้ผ่าน await จากภายนอกเท่านั้นโดยตรง ไม่ต้องซิงโครไนซ์
การสืบทอดจาก actor อื่นเท่านั้นแบบคลาสมาตรฐาน
ความสอดคล้องโปรโตคอลสามารถสอดคล้องกับโปรโตคอลได้มาตรฐาน
ประสิทธิภาพโอเวอร์เฮดต่ำกับการแยกเร็วกว่าไม่มีการซิงโครไนซ์

การสืบทอดของ Actor

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

swift
actor SavingsAccount: BankAccount {
    func applyInterest(rate: Double) {
        let interest = balance * rate
        balance += interest
    }
}

การเรียกเมธอดของ Actor แบบอะซิงโครนัส

การเรียกแบบอะซิงโครนัส เป็นกลไกสำหรับโต้ตอบกับ actor จากโค้ดภายนอก เนื่องจาก actor แยกสถานะของมัน การเข้าถึงสมาชิกของมันจากภายนอกจึงจำเป็นต้องมี await ซึ่งช่วยให้ Swift รับประกันว่าโค้ดที่เรียกไม่บล็อกเธรดและ actor สามารถประมวลผลคำขออื่น ๆ ได้

Actor ทั่วโลกและท้องถิ่น

นอกจากชนิดของ actor ที่ประกาศแล้ว Swift รองรับ actor ทั่วโลก — คุณลักษณะ @MainActor ซึ่งทำเครื่องหมายคลาส พร็อพเพอร์ตี้ หรือเมธอดว่าสามารถดำเนินการบนเธรดหลักได้ ซึ่งมีประโยชน์อย่างยิ่งสำหรับโค้ด UI ในแอปพลิเคชัน iOS

swift
@MainActor
class ViewModel: ObservableObject {
    @Published var title: String = ""
    
    func updateTitle() {
        // โค้ดนี้รับประกันว่าจะทำงานบนเธรดหลัก
        title = "New Title"
    }
}

การใช้ @MainActor ช่วยขจัดความจำเป็นในการเรียก DispatchQueue.main.async ด้วยตนเอง ทำให้โค้ดสะอาดและปลอดภัยยิ่งขึ้น คอมไพเลอร์ตรวจสอบว่าการสลับไปยังเธรดหลักเกิดขึ้นอย่างถูกต้อง

บริบท Nonisolated และ Actor-Isolated

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

ฟังก์ชัน Nonisolated

เมธอด nonisolated มีประโยชน์สำหรับการคำนวณที่ไม่ขึ้นอยู่กับสถานะที่เปลี่ยนแปลงได้ของ actor ตัวอย่างเช่น เมธอด formatBalance ไม่ได้เข้าถึง balance โดยตรง แต่เพียงจัดรูปแบบค่าที่ส่งมา — เมธอดเช่นนี้ปลอดภัยที่จะทำให้เป็น nonisolated

swift
actor BankAccount {
    private var balance: Double = 0
    
    nonisolated func formatBalance(amount: Double) -> String {
        return "$\(amount)"
    }
}

สมาชิก nonisolated ดำเนินการแบบซิงโครนัสและไม่ต้องการ await อย่างไรก็ตาม พวกมันไม่สามารถอ่านพร็อพเพอร์ตี้ที่ถูกแยกของ actor ได้โดยตรง หากเมธอด nonisolated ต้องการค่าจาก actor จะต้อง ส่งเป็นพารามิเตอร์

Reentrancy และการเข้าซ้ำ

Reentrancy เป็นกลไกที่อนุญาตให้เข้า actor ซ้ำในระหว่างรอการเรียกแบบอะซิงโครนัส หากไม่มี reentrancy actor อาจตายแบบตลอดไปหากหนึ่งในเมธอดของมันรออีกเมธอดที่รอเมธอดแรก

Reentrancy ทำงานอย่างไร

เมื่อโค้ดภายใน actor ดำเนินการ await actor จะระงับงานปัจจุบันและสามารถ ประมวลผลงานอื่น ที่อยู่ในคิวได้ หลังจาก await เสร็จสมบูรณ์ งานจะกลับมาดำเนินการต่อ สิ่งนี้ป้องกันการตายแบบแต่ต้องใช้ความระมัดระวัง: สถานะของ actor ระหว่างจุด await อาจเปลี่ยนแปลง

swift
actor DataProcessor {
    var cache: [Int: String] = [:]
    
    func process(id: Int) async -> String {
        if let cached = cache[id] {
            return cached
        }
        // await — จุดเข้าซ้ำ
        let result = await fetchData(id: id)
        // แคชอาจเปลี่ยนแปลงหลังจาก await — ตรวจสอบอีกครั้ง
        cache[id] = result
        return result
    }
}

นักพัฒนาต้องคำนึงถึงการเข้าซ้ำและตรวจสอบสถานะของ actor หลังจากจุด await ข้อผิดพลาดทั่วไปคือการสันนิษฐานว่าการแยกของ actor ยังคงอยู่ตลอด จุดพัก แบบอะซิงโครนัส ในทางปฏิบัติ ระหว่าง await และคำสั่งถัดไป สถานะอาจแตกต่างจากที่คาดไว้

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

Actor แตกต่างจากคลาสใน Swift อย่างไร?

Actor แยกสถานะของมันจากการแข่งข้อมูลโดยอัตโนมัติ จำเป็นต้องมี await สำหรับการเข้าถึงจากภายนอก คลาสไม่มีการป้องกันเช่นนี้ — นักพัฒนาต้องรับผิดชอบการซิงโครไนซ์ผ่านการล็อกหรือคิว Actor สืบทอดจาก actor เท่านั้น คลาสสืบทอดจากคลาส

สามารถสืบทอดจาก Actor ได้หรือไม่?

ได้ actor สามารถสืบทอดจาก actor อื่น คลาสย่อย จะได้รับพร็อพเพอร์ตี้และเมธอดที่ถูกแยกทั้งหมดของพ่อแม่ Actor ไม่สามารถสืบทอดจากคลาสได้เพราะคลาสไม่มีกลไกการแยกของ actor ในระดับคอมไพเลอร์

บริบท actor-isolated คืออะไร?

บริบท actor-isolated เป็นพื้นที่โค้ดที่อนุญาตให้เข้าถึงสถานะที่เปลี่ยนแปลงได้ของ actor โดยตรง ภายในเมธอดของ actor ที่ถูกทำเครื่องหมายว่าแยกไว้ (โดยค่าเริ่มต้น) สามารถอ่านและเขียนพร็อพเพอร์ตี้ได้โดยไม่ต้อง await คอมไพเลอร์ตรวจสอบขอบเขตการแยก

จะส่งข้อมูลจาก Actor ไปยังโค้ดภายนอกได้อย่างไร?

ข้อมูลจาก actor ถูกส่งผ่าน เมธอด async ที่คืนค่าชนิด Sendable หรือผ่านเมธอด nonisolated ที่รับค่าเป็นพารามิเตอร์ นอกจากนี้ยังสามารถสร้างพร็อพเพอร์ตี้ async ที่คืนภาพรวมของสถานะของ actor เป็นโครงสร้าง Sendable

Actor รองรับความสอดคล้องโปรโตคอลหรือไม่?

ได้ actor สามารถสอดคล้องกับโปรโตคอลได้ หากโปรโตคอลมี ข้อกำหนดที่ถูกแยก (actor-isolated) ข้อกำหนดเหล่านั้นจะกลายเป็นถูกแยกโดย actor โดยอัตโนมัติ สำหรับเมธอดแบบอะซิงโครนัสในโปรโตคอล สามารถระบุได้ว่าต้องเรียกบน actor เฉพาะโดยใช้เครื่องหมาย isolated

สรุป

  • Actor เป็นชนิดอ้างอิงที่มีการแยกข้อมูลอัตโนมัติ ถูกนำเสนอใน Swift 5.5+
  • การแยก ทำงานผ่านผู้ดำเนินการของ actor ที่ประมวลผลคำขอตามลำดับ
  • การเข้าถึงภายนอก actor จำเป็นต้องมี await — สิ่งนี้รับประกันว่าไม่มีการแข่งกัน
  • Nonisolated อนุญาตให้ประกาศเมธอดแบบซิงโครนัสที่ไม่เข้าถึงสถานะที่ถูกแยก
  • Actor ทั่วโลก (@MainActor) ขยายการแยกไปยังเธรดการดำเนินการทั้งหมด
  • Reentrancy ป้องกันการตายแบบโดยอนุญาตให้เข้า actor ซ้ำระหว่าง await

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม