Sobes.tech
Middle

Czy w tym przypadku konieczne jest użycie asynchronicznego executor'a?

sobes.tech AI

Odpowiedź od AI

Tak, jest to konieczne.

Podczas dostępu do actor spoza jego izolowanego kontekstu (w tym przypadku z kontekstu globalnego), kompilator gwarantuje bezpieczeństwo wątków, wymagając wykonania dostępu asynchronicznie.

// Protokół do demonstracji
protocol DataFetcher {
    func fetchData() async -> String
}

actor DataCache {
    var cache: [String: String] = [:]

    func updateCache(key: String, value: String) {
        cache[key] = value // Wykonywane w izolowanym kontekście aktora
    }

    func cachedData(forKey key: String) -> String? {
        return cache[key] // Wykonywane w izolowanym kontekście aktora
    }

    nonisolated func clearCacheIsolated() {
        // Ta funkcja jest oznaczona jako nonisolated i nie ma dostępu do stanu aktora
        // Aby uzyskać dostęp, wymaga wywołania asynchronicznego
    }
}


class DataLoader {
    let cache: DataCache // Odwołanie do aktora

    init(cache: DataCache) {
        self.cache = cache
    }

    func loadData(key: String) async -> String {
        // Asynchroniczny dostęp do aktora spoza
        if let cached = await cache.cachedData(forKey: key) {
            return cached
        }

        // ... logika ładowania danych ...
        let newData = "Data for \(key)"

        // Asynchroniczna aktualizacja aktora
        await cache.updateCache(key: key, value: newData)

        return newData
    }

    func attemptClearCacheAsync() async {
        // Asynchroniczne wywołanie metody aktora spoza
        await cache.clearCacheIsolated()
    }

    func attemptClearCacheDirect() {
        // Błąd kompilacji:
        // Metoda instancji 'clearCacheIsolated()' izolowana przez aktora nie może być
        // wywołana z kontekstu nieizolowanego
        // cache.clearCacheIsolated()
    }
}

W tym przykładzie:

  • Metody updateCache i cachedData są wykonywane w izolowanym kontekście DataCache i dostępne synchronicznie w obrębie aktora.
  • Odwołanie do cache.cachedData(forKey: key) i cache.updateCache(key: key, value: newData) z metody loadData (poza kontekstem actor) wymaga słowa kluczowego await, co wskazuje na wykonanie asynchroniczne i użycie asynchronicznego executor. Executor actor odpowiada za wykonywanie tych operacji w kolejności, gwarantując wyłączny dostęp do stanu actor.
  • Metoda clearCacheIsolated jest oznaczona jako nonisolated, ale nawet jej wywołanie asynchroniczne await cache.clearCacheIsolated() jest poprawne spoza actor, choć nie jest to konieczne do zapewnienia bezpieczeństwa wątków (ponieważ metoda nie zmienia stanu actor).
  • Bezpośrednie wywołanie synchroniczne cache.clearCacheIsolated() z kontekstu nieizolowanego (np. w attemptClearCacheDirect) powoduje błąd kompilacji, potwierdzając konieczność dostępu asynchronicznego.

W związku z tym, aby bezpiecznie współdziałać z actor spoza jego kontekstu, konieczne jest używanie wywołań asynchronicznych, które są wykonywane przy pomocy asynchronicznego executor zarządzanego przez samego aktora.