3. Executor: Tulang Punggung Isolation
3. Executor: Tulang Punggung Isolation
Executor adalah abstraksi runtime yang menjadwalkan job di actor. Memahami executor berarti memahami siapa yang menjalankan kode actor dan di mana.
SerialExecutor Protocol
Setiap actor punya executor yang konform ke SerialExecutor:
public protocol SerialExecutor: Executor {
func enqueue(_ job: consuming ExecutorJob)
func asUnownedSerialExecutor() -> UnownedSerialExecutor
}
Default-nya, actor pakai default actor executor — implementasi yang dikelola runtime, mirip serial queue lightweight.
Custom Executor: Mengikat Actor ke Thread Tertentu
Kadang kamu butuh actor yang selalu berjalan di queue tertentu — misalnya CoreData context queue, atau DispatchQueue legacy. Override unownedExecutor:
actor DatabaseActor {
private let queue: DispatchSerialQueue
private let _executor: any SerialExecutor
init(queue: DispatchSerialQueue) {
self.queue = queue
self._executor = queue.asUnownedSerialExecutor() as! any SerialExecutor
}
nonisolated var unownedExecutor: UnownedSerialExecutor {
queue.asUnownedSerialExecutor()
}
func query() { /* dijalankan di `queue` */ }
}
Use case nyata:
- Bridging dengan API berbasis
DispatchQueueyang tidak bisa diubah. - Memastikan akses hardware (kamera, sensor, GPU) selalu di queue yang benar.
- Integrasi dengan CoreData (
NSManagedObjectContextqueue).
Hati-hati: kalau executor yang kamu pasang tidak benar-benar serial (atau bisa deadlock dengan dirinya), garansi actor pecah. DispatchSerialQueue aman; concurrent queue tidak.
Global Executors
Beberapa executor "tunggal" disediakan runtime:
MainActor.shared.unownedExecutor— executor di main thread.GlobalActorapapun — executor yang ditentukan implementasinya.- Detached
Tasktanpa actor → cooperative thread pool.
Mengukur Executor Saat Runtime
Untuk debugging, kamu bisa memeriksa "di mana saya saat ini":
@inlinable
func currentExecutorDescription() -> String {
if Thread.isMainThread { return "main thread" }
return "background (\(Thread.current.name ?? "unnamed"))"
}
actor Worker {
func process() {
print(currentExecutorDescription()) // background biasanya
}
}