Sobes.tech
Middle+

Ko jūs zināt par lasītāja un rakstnieka problēmu?

sobes.tech AI

Atbilde no AI

Lasītāja un rakstītāja problēma ir klasiska sinhronizācijas uzdevums kopīgu datu pieejamības nodrošināšanai daudzšūnu vidē.

Problēmas būtība:

  • Daudz pavedienu (lasītāji) vienlaikus lasa datus.
  • Daudz pavedienu (rakstītāji) vienlaikus maina datus.

Prasības:

  • Lasītāji var lasīt vienlaikus bez ierobežojumiem.
  • Rakstītājiem ir ekskluzīva piekļuve datiem (kamēr rakstītājs strādā, neviens cits – ne lasītāji, ne rakstītāji – nevar piekļūt).
  • Vienlaikus var strādāt tikai viens rakstītājs.
  • Ja rakstītājs gaida piekļuvi, jauni lasītāji tam nedrīkst piešķirt piekļuvi līdz rakstītājs pabeigs savu darbu. Šis noteikums novērš "rakstītāju badu".

Risinājumi iOS:

  • NSLock: Vienkāršākais mehānisms, bet ne optimāls šim uzdevumam, jo bloķē gan lasīšanu, gan rakstīšanu.

  • NSRecursiveLock: Atļauj vienam un tam pašam pavedienam vairākas reizes iegūt bloķējumu. Nav lietojams.

  • NSCondition: Elastīgāks mehānisms, kas ļauj pavedieniem gaidīt noteiktus nosacījumus. To var izmantot lasītāju/rakstītāju loģikas īstenošanai, bet tas prasa manuālu bloķēšanas un nosacījumu pārvaldību.

  • Serial Dispatch Queue (GCD): Izveidojiet vienu rindu visām lasīšanas un rakstīšanas operācijām. Rakstīšanas operācijas tiek izpildītas sinhroni, lasīšana var tikt veikta asinhroni, bet tikai pēc iepriekšējo operāciju pabeigšanas. Šis ir vienkāršs risinājums, bet ne optimāls lasīšanai, jo lasīšana nevar notikt paralēli.

    let readWriteQueue = DispatchQueue(label: "com.example.readwrite", attributes: .concurrent)
    
    func readData() {
        readWriteQueue.async {
            // Datu lasīšanas loģika
            print("Lasu datus...")
        }
    }
    
    func writeData() {
        readWriteQueue.sync(flags: .barrier) {
            // Datu rakstīšanas loģika
            print("Rakstu datus...")
        }
    }
    
  • Konkurējoša Dispatch Queue ar Barrier (GCD): Vislabākais risinājums lielākajā daļā gadījumu. Izmanto konkurējošu rindu paralēlai lasīšanai. Rakstīšanai tiek izmantots .barrier marķieris. Kad .barrier operācija ir rindā, tā gaida, līdz visas iepriekšējās operācijas pabeigsies, pēc tam tā pati tiek izpildīta, un kamēr tā notiek, citas operācijas (ne lasīšana, ne rakstīšana) netiek veiktas. Pēc barjeras operācijas rinda atkal kļūst konkurējoša. Tādējādi lasīšana notiek paralēli, bet rakstīšana ir ekskluzīva.

    let readWriteQueue = DispatchQueue(label: "com.example.readwrite", attributes: .concurrent)
    
    func readData() {
        readWriteQueue.async {
            // Datu lasīšanas loģika
            print("Lasu datus...")
        }
    }
    
    func writeData() {
        readWriteQueue.sync(flags: .barrier) {
            // Datu rakstīšanas loģika
            print("Rakstu datus...")
        }
    }
    

    Tas pats kods kā sērijas rindas gadījumā, bet atribīts .concurrent padara rindu konkurētspējīgu. .barrier marķieris liek rindai darboties kā secīgai tikai šai konkrētajai operācijai.

  • os_unfair_lock (iOS 10+): Zema līmeņa aizslēgs, kas ir efektīvāks nekā NSLock. To var izmantot sarežģītākas lasītāju/rakstītāju loģikas īstenošanai manuāli, ja nepieciešams maksimālais veiktspējas vai specifisks uzvedības līmenis. Prasa uzmanību lietojot.

Izvēle ir atkarīga no konkrētajām lietojuma prasībām, lasīšanas un rakstīšanas operāciju biežuma un nepieciešamā veiktspējas līmeņa. Visbiežāk, izmantot konkurējošu dispatch rindu ar .barrier marķieri ir vislabākā un ieteicamākā pieeja iOS.