Section 3/161 menit

3. Teori: Cooperative Thread Pool dan Task Scheduling

3. Teori: Cooperative Thread Pool dan Task Scheduling

Cara Kerja Cooperative Thread Pool

Swift Concurrency menggunakan cooperative multitasking — berbeda dari preemptive threading di GCD. Dalam cooperative model:

  • Thread tidak di-preempt paksa oleh OS scheduler
  • Task hanya berpindah thread saat mencapai suspension point (await)
  • Jumlah thread = jumlah CPU core (tidak membengkak seperti GCD)
  • Setiap thread punya local queue + shared global queue
swift
CPU Core 1: Thread A
  Task 1 ─── await ─── Task 2 ─── await ─── Task 1 (resume)
                         │
                     Task 2 bisa lanjut di Core 2

CPU Core 2: Thread B
  Task 3 ─── await ─── Task 2 (dilanjutkan dari Core 1)

Ketika await dipanggil:

  1. Task menyimpan continuation (sisa kode setelah await)
  2. Thread dibebaskan untuk Task lain
  3. Ketika async operation selesai, continuation di-schedule ke thread yang tersedia
  4. Task tidak dijamin resume di thread yang sama — kecuali di actor

Priority dan Priority Inversion

Setiap Task punya priority: .background, .utility, .default, .userInitiated, .userInteractive.

swift
// Task dengan priority eksplisit
Task(priority: .userInitiated) {
    await criticalOperation()
}

Task(priority: .background) {
    await bulkDataSync()
}

// Child Task mewarisi priority parent
Task {  // priority: .default (inherited dari context)
    async let a = Task(priority: .userInitiated) { await fetchData() }
    // a masih berjalan di .userInitiated meski parent .default
}

Priority Inversion terjadi ketika task high-priority menunggu task low-priority. Swift Concurrency mencegah ini dengan priority escalation: ketika task .userInitiated menunggu task .background, priority task .background di-naikkan sementara.

swift
// Swift otomatis handle priority escalation
actor DataStore {
    func processHighPriority() async {
        // Task ini: .userInitiated
        await processLow()  // task di sini: .background → dinaikkan ke .userInitiated sementara
    }

    func processLow() async {
        // Meski dibuat sebagai .background, saat ditunggu .userInitiated,
        // prioritynya di-escalate otomatis
    }
}

Job dan Executor

Di balik Task, ada konsep Job — unit kerja terkecil yang bisa di-schedule. Setiap await membagi Task menjadi serangkaian Jobs.

Executor adalah objek yang menerima dan menjalankan Jobs:

  • SerialExecutor: jalankan satu job sekaligus (dipakai actor)
  • Global cooperative pool executor: default untuk unstructured Tasks
  • Main actor executor: dispatch ke main thread
swift
Task ──await──► Job1 ──► Executor (runs on thread) ──► Job2 ──► Executor ──► Job3
                          (resume ketika await selesai)