Sobes.tech
Middle+

O'quvchi va yozuvchi muammosi haqida nima bilasiz?

sobes.tech AI

AIdan javob

O'qiyuvchi va yozuvchi muammosi, ko'p ipli muhitda umumiy ma'lumotlarga kirishni sinxronlashtirishning klassik vazifasidir.

Muammoning mohiyati:

  • Bir nechta iplar (o'qiyuvchilar) ma'lumotlarni bir vaqtning o'zida o'qiydi.
  • Bir nechta iplar (yozuvchilar) ma'lumotlarni bir vaqtning o'zida o'zgartiradi.

Talablar:

  • O'qiyuvchilar cheklovlarsiz bir vaqtning o'zida o'qiy oladi.
  • Yozuvchilar ma'lumotlarga eksklyuziv kirishga ega (bir yozuvchi ishlayotgan paytda, hech kim, na o'qiyuvchi, na yozuvchi, kirish huquqiga ega bo'lmaydi).
  • Bir vaqtning o'zida faqat bitta yozuvchi ishlashi mumkin.
  • Agar yozuvchi kirishni kutayotgan bo'lsa, yangi o'qiyuvchilar uni kutmasligi kerak, yozuvchi ishini tugatgach. Bu qoidalar yozuvchilarning "ochlik" muammosini oldini oladi.

iOS'da yechimlar:

  • NSLock: Eng oddiy mexanizm, ammo bu vazifa uchun optimal emas, chunki u o'qish va yozishni bloklaydi.

  • NSRecursiveLock: O'zining ipi uchun blokni bir necha marta olishi mumkin. Amalga oshirilmaydi.

  • NSCondition: Ko'proq moslashuvchan mexanizm, iplarning muayyan shartlarni kutishiga imkon beradi. O'qiyuvchilar/yozuvchilar mantiqini amalga oshirish uchun ishlatilishi mumkin, ammo blokirovka va shartlarni qo'lda boshqarishni talab qiladi.

  • Serial Dispatch Queue (GCD): Barcha o'qish va yozish operatsiyalari uchun ketma-ket navbat yaratish. Yozish sinxron bajariladi, o'qish esa asinxron bajarilishi mumkin, lekin faqat avvalgi operatsiyalar tugagach. Bu oddiy yechim, ammo o'qish uchun optimal emas, chunki o'qish parallel bo'la olmaydi.

    let readWriteQueue = DispatchQueue(label: "com.example.readwrite", attributes: .concurrent)
    
    func readData() {
        readWriteQueue.async {
            // Ma'lumotlarni o'qish mantiqi
            print("Ma'lumotlar o'qilmoqda...")
        }
    }
    
    func writeData() {
        readWriteQueue.sync(flags: .barrier) {
            // Ma'lumotlarni yozish mantiqi
            print("Ma'lumotlar yozilmoqda...")
        }
    }
    
  • Barrier bilan Concurrent Dispatch Queue (GCD): Ko'p hollarda eng yaxshi yechim. O'qish operatsiyalarini parallel bajarish uchun concurrent navbatdan foydalaniladi. Yozish uchun .barrier flag ishlatiladi. Bu flag bilan navbatga qo'yilgan operatsiya, avvalgi barcha operatsiyalar tugashini kutadi, so'ng bajariladi va uning davomida boshqa hech qanday operatsiya (o'qish yoki yozish) bajarilmaydi. Tugagach, navbat yana concurrent bo'ladi. Shu bilan, o'qish parallel bo'ladi, yozish esa eksklyuziv.

    let readWriteQueue = DispatchQueue(label: "com.example.readwrite", attributes: .concurrent)
    
    func readData() {
        readWriteQueue.async {
            // Ma'lumotlarni o'qish mantiqi
            print("Ma'lumotlar o'qilmoqda...")
        }
    }
    
    func writeData() {
        readWriteQueue.sync(flags: .barrier) {
            // Ma'lumotlarni yozish mantiqi
            print("Ma'lumotlar yozilmoqda...")
        }
    }
    

    Bu, ketma-ket navbat uchun kod bilan bir xil, ammo .concurrent atributi navbatni concurrent qiladi. .barrier flag esa, navbatni faqat bu operatsiya uchun ketma-ket bo'lishini ta'minlaydi.

  • os_unfair_lock (iOS 10+): Past darajadagi blokirovka, NSLockdan ko'ra samaraliroq. Maksimal ishlash yoki maxsus xatti-harakatlar uchun, o'qiyuvchilar/yozuvchilar mantiqini qo'lda amalga oshirish uchun ishlatilishi mumkin. Ehtiyotkorlik bilan foydalanish talab etiladi.

Yechim tanlovi, ilovaning aniq talablariga, o'qish va yozish operatsiyalarining tezligiga va kerakli ishlash darajasiga bog'liq. Ko'p hollarda, .barrier flag bilan concurrent dispatch queue ishlatish, iOSda eng muvozanatli va tavsiya etilgan yondashuvdir.