Ko'p tarmoqli ilovalar. Ko'p bosqichli ilovalar arxitekturalari Ko'p bosqichli ilovalar

Mavzular va jarayonlar hisoblashda o'zaro bog'liq tushunchalardir. Ikkalasi ham ma'lum bir tartibda bajarilishi kerak bo'lgan ko'rsatmalar ketma-ketligidir. Alohida mavzular yoki jarayonlardagi ko'rsatmalar parallel ravishda ishlashi mumkin.

Jarayonlar operatsion tizimda mavjud bo'lib, foydalanuvchilar dastur yoki ilovalar sifatida ko'rgan narsalarga mos keladi. Boshqa tomondan, ip jarayon ichida mavjud. Shu sababli, iplar ba'zan "engil jarayonlar" deb ataladi. Har bir jarayon bir yoki bir nechta ipdan iborat. Bir nechta jarayonlarning mavjudligi kompyuterga bir nechta vazifalarni "bir vaqtning o'zida" bajarishga imkon beradi. Bir nechta iplarning mavjudligi jarayonga parallel bajarish uchun ishni almashish imkonini beradi. Ko'p protsessorli kompyuterda jarayonlar yoki oqimlar turli protsessorlarda ishlashi mumkin. Bu haqiqiy parallel ishlash imkonini beradi.

To'liq parallel ishlov berish har doim ham mumkin emas. Oqimlar ba'zan sinxronlashtirilishi kerak. Bitta ip boshqa ish zarrachasining natijasini kutayotgan bo‘lishi mumkin yoki bitta ip boshqa ip tomonidan foydalanilayotgan resursga eksklyuziv kirishni talab qilishi mumkin. Sinxronizatsiya muammolari ko'p bosqichli ilovalardagi xatolarning keng tarqalgan sababidir. Ba'zida mavzu hech qachon mavjud bo'lmaydigan resursni kutishi mumkin. Bu o'lik deb ataladigan holat bilan tugaydi.

O'rganish kerak bo'lgan birinchi narsa jarayon kamida bitta ipdan iborat... Operatsion tizimda har bir jarayonda manzil maydoni va bitta boshqaruv ipi mavjud. Aslida, bu jarayonni belgilaydi.

Bir tomondan, jarayonni tegishli resurslarni bir guruhga birlashtirish usuli sifatida qarash mumkin... Jarayon dastur matni va ma'lumotlarini, shuningdek, boshqa resurslarni o'z ichiga olgan manzil maydoniga ega. Resurslar ochiq fayllar, bolalar jarayonlari, boshqarilmaydigan signallar, signal ishlov beruvchilari, hisobga olish ma'lumotlari va boshqalar. Resurslarni jarayon shaklida birlashtirish orqali boshqarish ancha oson.

Boshqa tomondan, jarayonni bajariladigan qo'shma buyruqlar to'plami yoki shunchaki ip sifatida ko'rish mumkin... Ipda amallarning bajarilish tartibini kuzatuvchi buyruq hisoblagichi mavjud. U joriy o'zgaruvchilarni saqlaydigan registrlarga ega. U jarayonni bajarish protokolini o'z ichiga olgan stekga ega, bu erda har bir chaqirilgan, lekin hali qaytarilmagan protsedura uchun alohida ramka ajratilgan. Garchi ip jarayon ichida bajarilishi kerak bo'lsa-da, siz ip va jarayon tushunchalarini farqlashingiz kerak.Jarayonlar resurslarni guruhlash uchun ishlatiladi va iplar CPUda navbatma-navbat bajariladigan ob'ektlardir.

Oqimlar tushunchasi qo'shimcha qiladi jarayon modeliga bir jarayon muhitida bir vaqtning o'zida bir nechta dasturlarni bajarish imkoniyati nisbatan mustaqildirlar. Bitta jarayonda parallel ravishda ishlaydigan bir nechta ish zarralari bir xil kompyuterda parallel ravishda ishlaydigan bir nechta jarayonlarga o'xshaydi. Birinchi holda, iplar manzil maydonini, ochiq fayllarni va boshqa resurslarni almashadi. Ikkinchi holda, jarayonlar jismoniy xotira, disklar, printerlar va boshqa resurslarni almashadi. Oqimlar jarayonlarning ba'zi xususiyatlariga ega, shuning uchun ular ba'zan engil jarayonlar deb ataladi. Muddati ko'p tarmoqli bir jarayonda bir nechta iplardan foydalanishni tasvirlash uchun ham ishlatiladi.

Har qanday oqimdan iborat ikkita komponent:

yadro obyekti bu orqali operatsion tizim oqimni boshqaradi. Oqim haqidagi statistik ma’lumotlar ham u yerda saqlanadi (qo‘shimcha oqimlar yadro tomonidan ham yaratiladi);
iplar to'plami, u kodni bajarish uchun ip kerak bo'lgan barcha funktsiyalar va mahalliy o'zgaruvchilarning parametrlarini o'z ichiga oladi.

Chiziqni umumlashtirib, keling, tuzatamiz: jarayonlar va iplar o'rtasidagi asosiy farq, shundan iboratki, jarayonlar bir-biridan ajratilgan, shuning uchun ular turli manzil bo'shliqlaridan foydalanadilar va iplar bir-biriga aralashmasdan harakatlarni bajarishda bir xil bo'shliqdan (jarayon ichida) foydalanishi mumkin. Bu nima ko'p bosqichli dasturlashning qulayligi: Ilovani bir nechta ketma-ket oqimlarga bo'lish orqali biz unumdorlikni oshirishimiz, foydalanuvchi interfeysini soddalashtirishimiz va kengayish qobiliyatiga erishishimiz mumkin (agar sizning ilovangiz ko'p protsessorli tizimda o'rnatilgan bo'lsa, turli protsessorlarda iplarni bajarsa, dasturingiz hayratlanarli tezlikda ishlaydi =)) .

1. Tarmoq jarayonda kodni bajarish ketma-ketligini belgilaydi.

2. Jarayon hech narsani bajarmaydi, u faqat iplar uchun konteyner bo'lib xizmat qiladi.

3. Oqimlar har doim jarayon kontekstida yaratiladi va ularning butun hayoti faqat uning chegaralari ichida sodir bo'ladi.

4. Mavzular bir xil kodni bajarishi va bir xil ma'lumotlarni manipulyatsiya qilishi, shuningdek, yadro ob'ektlarining deskriptorlarini almashishi mumkin, chunki deskriptorlar jadvali alohida oqimlarda emas, balki jarayonlarda yaratiladi.

5. Mavzular jarayonlarga qaraganda sezilarli darajada kamroq resurslarni iste'mol qilganligi sababli, qo'shimcha iplardan foydalanish orqali muammolaringizni hal qilishga harakat qiling va yangi jarayonlar yaratishdan saqlaning (lekin bu borada aqlli bo'ling).

Ko'p vazifalarni bajarish(ing. ko'p vazifa) - bir nechta jarayonlarni parallel (yoki psevdoparallel) qayta ishlash imkoniyatini ta'minlash uchun operatsion tizim yoki dasturlash muhitining xususiyati. Haqiqiy operatsion tizimning ko'p vazifalari faqat taqsimlangan hisoblash tizimlarida mumkin.

Fayl: GNOME ish stoli muhiti, Firefox, Tor va VLC Player.jpg bilan ishlaydigan Debian (7.1 versiyasi, "Wheezy") skrinshoti.

Bir nechta jarayonlarning faolligini aks ettiruvchi zamonaviy operatsion tizimning ish stoli.

Multitaskingning 2 turi mavjud:

· Ko‘p vazifali jarayon(jarayonlar asosida - bir vaqtda bajariladigan dasturlar). Bu erda dastur operatsion tizimning rejalashtiruvchisi tomonidan boshqarilishi mumkin bo'lgan eng kichik kod qismidir. Ko'pchilik foydalanuvchilarga yaxshi ma'lum (matn muharririda ishlash va musiqa tinglash).

· Ko'p vazifali mavzu(oqimga asoslangan). Boshqariladigan kodning eng kichik birligi ipdir (bitta dastur bir vaqtning o'zida 2 yoki undan ortiq vazifani bajarishi mumkin).

Multithreading - bu ko'p vazifani bajarishning ixtisoslashgan shakli.

1 Ko'p vazifali muhitning xususiyatlari

2 Ko'p vazifali muhitni amalga oshirishdagi qiyinchiliklar

3 Ko'p vazifali operatsion tizimlar tarixi

Pseudo-parallel multitaskingning 4 turi

o 4.1 Oldindan bo'lmagan ko'p vazifa

o 4.2 Birgalikda yoki hamkorlikda ko'p vazifalarni bajarish

o 4.3 Preemptive yoki prioritet multitasking (real vaqt rejimi)

5 Ko'p vazifali tizimlardagi muammoli vaziyatlar

o 5.1 Ochlik

o 5.2 Poyga holati

· 7 ta eslatma

Ko'p vazifali muhitning xususiyatlari [tahrirlash | manbani tahrirlash]

Primitiv ko'p vazifali muhitlar toza "resurs almashish" ni ta'minlaydi, bunda har bir vazifaga xotiraning ma'lum bir qismi ajratiladi va vazifa qat'iy belgilangan vaqt oralig'ida chaqiriladi.

Ilg'or ko'p vazifali tizimlar vazifa xotirada boshlanganda yoki xotiradan chiqib ketganda, uning ustuvorligi va tizim strategiyasiga qarab resurslarni dinamik ravishda taqsimlaydi. Ushbu ko'p vazifali muhit quyidagi xususiyatlarga ega:

Har bir vazifa o'z ustuvorligiga ega, unga muvofiq u protsessor vaqtini va xotirasini oladi

Tizim vazifalar navbatlarini tashkil qiladi, shunda barcha vazifalar tizimning ustuvorliklari va strategiyasiga qarab resurslarni oladi

Tizim uzilishlarni qayta ishlashni tashkil qiladi, unga ko'ra vazifalarni faollashtirish, o'chirish va o'chirish mumkin.

· Belgilangan vaqt oralig'i tugagandan so'ng, yadro boshqa vazifalarga resurslarni berib, topshiriqni vaqtincha bajarilish holatidan tayyor holatga o'tkazadi. Agar xotira etishmayotgan bo'lsa, bajarilmaydigan vazifalar sahifalari diskka oldindan o'rnatilishi (almashtirilishi) va tizim tomonidan ma'lum vaqtdan so'ng xotirada tiklanishi mumkin.

Tizim vazifaning manzil maydonini boshqa vazifalarning ruxsatsiz aralashuvidan himoya qiladi

Tizim o'z yadrosining manzil maydonini vazifalarning ruxsatsiz aralashuvidan himoya qiladi

Tizim alohida vazifalarning ishdan chiqishi va muzlashini aniqlaydi va ularni to'xtatadi

Tizim resurslar va qurilmalarga kirishdagi nizolarni hal qiladi, bu esa bloklangan resurslarni kutishning umumiy to'xtab qolishining oldini oladi.

Tizim har bir vazifani ertami-kechmi faollashishini kafolatlaydi

Tizim real vaqtda so'rovlarni qayta ishlaydi

Tizim jarayonlar o'rtasidagi aloqani ta'minlaydi

Ko'p vazifali muhitni amalga oshirishdagi qiyinchiliklar [tahrirlash | manbani tahrirlash]

Ko'p vazifali muhitni amalga oshirishdagi asosiy qiyinchilik uning ishonchliligi bo'lib, xotirani himoya qilish, nosozliklar va uzilishlarni qayta ishlash, muzlatish va blokirovkalarni oldini olishda ifodalanadi.

Ishonchli bo'lishdan tashqari, ko'p vazifali muhit samarali bo'lishi kerak. Uni saqlash uchun resurslarning narxi: jarayonlarga xalaqit bermasligi, ularning ishini sekinlashtirmasligi, xotirani keskin cheklamasligi kerak.

Ko'p tarmoqli- platformaning xossasi (masalan, operatsion tizim, virtual mashina va boshqalar) yoki operatsion tizimda paydo bo'lgan jarayon bir nechtadan iborat bo'lishi mumkin bo'lgan dastur. oqimlar"parallel", ya'ni o'z vaqtida belgilangan tartibsiz ishlaydi. Ba'zi vazifalar uchun bu ajratish kompyuter resurslaridan yanada samarali foydalanishga erishish mumkin.

Bunday oqimlar ham chaqiriladi ijro iplari(ingliz tilidan. ijro chizig'i); ba'zan "iplar" deb ataladi (ingliz tilining so'zma-so'z tarjimasi. ip) yoki norasmiy "iplar".

Ko'p oqimning mohiyati bitta bajariladigan jarayon darajasida kvazi-ko'p vazifalarni bajarishdir, ya'ni barcha oqimlar jarayonning manzil maydonida bajariladi. Bundan tashqari, jarayondagi barcha iplar nafaqat umumiy manzil maydoniga, balki umumiy fayl identifikatorlariga ham ega. Ishlayotgan jarayonda kamida bitta (asosiy) oqim mavjud.

Multitaskingni (dasturlash doktrinasi sifatida) ko'p vazifali yoki ko'p ishlov berish bilan aralashtirib yubormaslik kerak, garchi ko'p vazifani amalga oshiradigan operatsion tizimlar odatda ko'p ish zarralarini ham amalga oshiradi.

Dasturlashda multithreadingning afzalliklari quyidagilardan iborat:

· Umumiy manzil maydonidan foydalanish orqali dasturni ayrim hollarda soddalashtirish.

· Jarayonga nisbatan oqim yaratishga kamroq vaqt sarflanadi.

· Protsessor hisoblari va kiritish-chiqarish operatsiyalarini parallellashtirish hisobiga jarayon unumdorligini oshirish.

1 Streamni amalga oshirish turlari

2 Iplarning o'zaro ta'siri

3 Terminologiyaning tanqidi

· 6 ta eslatma

Streamni amalga oshirish turlari [tahrirlash | manbani tahrirlash]

· Foydalanuvchi maydonida oqim. Har bir jarayon yadro jarayonlari jadvaliga o'xshash mavzular jadvaliga ega.

Ushbu turdagi afzalliklari va kamchiliklari quyidagilardan iborat: Kamchiliklari

1. Bitta jarayonda taymer uzilishining yo'qligi

2. Jarayon uchun blokirovka qiluvchi tizim so'rovidan foydalanilganda, uning barcha iplari bloklanadi.

3. Amalga oshirishning murakkabligi

· Yadro bo'shlig'idagi mavzu. Jarayon jadvali bilan bir qatorda yadro maydonida iplar jadvali mavjud.

· "Tolalar" (ing. tolalar). Bitta yadro rejimida ishlaydigan bir nechta foydalanuvchi rejimi. Yadro bo'shlig'i oqimi sezilarli resurslarni, birinchi navbatda, jismoniy xotirani va yadro rejimi stekining yadro rejimidagi manzil diapazonini sarflaydi. Shu sababli, "tola" tushunchasi kiritildi - faqat foydalanuvchi rejimida bajariladigan engil oqim. Har bir oqimda bir nechta "tolalar" bo'lishi mumkin.

Mavzularning o'zaro ta'siri [tahrirlash | manbani tahrirlash]

Ko'p tarmoqli muhitda ko'pincha bir xil ma'lumotlar yoki qurilmalarni parallel bajaruvchi iplar yordamida ishlatish bilan bog'liq muammolar paydo bo'ladi. Bunday muammolarni hal qilish uchun iplarning o'zaro ta'sirining o'zaro istisnolar (mutexlar), semaforlar, tanqidiy bo'limlar va hodisalar kabi usullari qo'llaniladi.

· O'zaro istisnolar (mutex, mutex) sinxronizatsiya ob'ekti bo'lib, u har qanday ip bilan band bo'lmaganda maxsus signal holatiga o'rnatiladi. Istalgan vaqtda ushbu ob'ektga faqat bitta ip egalik qiladi, shuning uchun bunday ob'ektlarning nomi (ingliz tilidan mut odatda masalan klyuziv kirish - o'zaro eksklyuziv kirish) - umumiy manbaga bir vaqtning o'zida kirish istisno qilinadi. Barcha kerakli harakatlar bajarilgandan so'ng, mutex chiqariladi, bu boshqa mavzularga umumiy manbaga kirish imkonini beradi. Ob'ekt bir xil ip orqali ikkinchi marta rekursiv suratga olishni qo'llab-quvvatlashi mumkin, ipni bloklamasdan hisoblagichni oshiradi va keyin bir nechta ajratishni talab qiladi. Bu, masalan, Win32-dagi muhim bo'lim. Biroq, buni qo'llab-quvvatlamaydigan ba'zi ilovalar mavjud va rekursiv suratga olishga urinishda ipni blokirovka qilishga olib keladi. Bu Windows yadrosidagi FAST_MUTEX.

· Semaforlar resurs puli bo'sh bo'lgunga qadar bir vaqtning o'zida bir nechta oqimlar tomonidan olinishi mumkin bo'lgan mavjud resurslarni ifodalaydi. Keyin qo'shimcha oqimlar kerakli miqdordagi resurslar yana mavjud bo'lguncha kutishlari kerak. Semaforlar juda samarali, chunki ular resurslarga bir vaqtda kirish imkonini beradi. Semafor mutexning mantiqiy kengaytmasidir - hisoblagichi 1 bo'lgan sema mutexga ekvivalent, lekin hisoblagich 1 dan ortiq bo'lishi mumkin.

· Ishlanmalar. 1 bitli "signal berilgan yoki yo'q" ma'lumotlarini saqlaydigan ob'ekt, uning ustida "signal", "signalsiz holatga qaytarish" va "kutish" operatsiyalari aniqlanadi. Signalli hodisani kutish - bu ipning bajarilishini darhol davom ettirish bilan operatsiyaning yo'qligi. Tanlanmagan hodisani kutish boshqa ip (yoki OT yadrosidagi uzilishni qayta ishlashning ikkinchi bosqichi) voqea haqida signal bermaguncha ipning to'xtatilishiga olib keladi. "Har qanday" yoki "barcha" rejimlarida bir nechta hodisalarni kutish mumkin. Bundan tashqari, birinchi va yagona - kutish ipi uyg'ongandan so'ng avtomatik ravishda signalsiz holatga qaytariladigan hodisani yaratish mumkin (bunday ob'ekt "tanqidiy qism" ob'ektini amalga oshirish uchun asos sifatida ishlatiladi). Ular MS Windows da foydalanuvchi rejimida ham, yadro rejimida ham faol foydalaniladi. Linux yadrosida kwait_queue deb nomlangan shunga o'xshash ob'ekt mavjud.

· Kritik bo'limlar mutekslarga o'xshash sinxronizatsiyani ta'minlaydi, bundan mustasno, kritik bo'limlarni ifodalovchi ob'ektlar bir xil jarayonda mavjud. Hodisalar, mutekslar va semaforlar bitta jarayonli dasturda ham qo'llanilishi mumkin, ammo ba'zi operatsion tizimlarda (masalan, Windows NT kabi) muhim bo'limlarni amalga oshirish tez va samarali o'zaro eksklyuziv sinxronizatsiya mexanizmini ta'minlaydi - muhim bo'lgan olish va chiqarish operatsiyalari. bo'lim OT yadrosiga olib keladigan har qanday tizim qo'ng'iroqlarini oldini olish uchun bitta ish zarrachasi uchun optimallashtirilgan (nizosiz). Mutekslar singari, muhim bo'limni ifodalovchi ob'ekt bir vaqtning o'zida faqat bitta oqim tomonidan ishlatilishi mumkin, bu ularni umumiy resurslarga kirishni cheklash uchun juda foydali qiladi.

· Shartli o'zgaruvchilar (condvars). Ular hodisalarga o'xshaydi, lekin ular xotirani egallaydigan ob'ektlar emas - faqat o'zgaruvchining manzili ishlatiladi, "o'zgaruvchining mazmuni" tushunchasi mavjud emas, shartli o'zgaruvchi sifatida ixtiyoriy ob'ektning manzilidan foydalanish mumkin. . Voqealardan farqli o'laroq, shart o'zgaruvchisini signalli holatga o'rnatish, agar hozirda o'zgaruvchida hech qanday mavzu kutilmasa, hech qanday oqibatlarga olib kelmaydi. Xuddi shunday holatda hodisani o'rnatish "signallangan" holatni hodisaning o'zida saqlashni talab qiladi, shundan so'ng voqeani kutishni istagan keyingi oqimlar to'xtamasdan darhol bajarilishini davom ettiradi. Bunday ob'ektdan to'liq foydalanish uchun, shuningdek, mutexni bo'shatish va shartli o'zgaruvchini atomik tarzda kutish kerak. Ular UNIX-ga o'xshash operatsion tizimlarda keng qo'llaniladi. Hodisalar va shart o'zgaruvchilarning afzalliklari va kamchiliklari haqidagi munozaralar Windows va UNIX ning afzalliklari va kamchiliklari haqidagi muhokamalarning muhim qismidir.

IO tugatish porti (IOCP). OT yadrosida amalga oshirilgan va tizim chaqiruvlari orqali "tuzilmani navbatning dumiga qo'yish" va "navbat boshidan keyingi tuzilmani olish" operatsiyalari bilan kirish mumkin bo'lgan "navbat" ob'ekti - oxirgi qo'ng'iroq bajarilishini to'xtatib turadi. agar navbatda bo'sh bo'lsa va boshqa ip "qo'yish" ga qo'ng'iroq qilmaydi. IOCP ning eng muhim xususiyati shundaki, tuzilmalar unga nafaqat foydalanuvchi rejimidan aniq tizim qo'ng'irog'i orqali, balki fayl identifikatorlaridan birida bajarilgan asinxron kiritish-chiqarish operatsiyasi natijasida OS yadrosi ichida yashirin ravishda joylashtirilishi mumkin. Ushbu ta'sirga erishish uchun tizim chaqiruvi "FIY identifikatorini IOCP bilan bog'lash" dan foydalanishingiz kerak. Bunday holda, navbatga qo'yilgan struktura kiritish-chiqarish operatsiyasining xato kodini o'z ichiga oladi, shuningdek, agar bu operatsiya muvaffaqiyatli bo'lsa, haqiqiy kirish yoki chiqish baytlari soni. Tugatish portini amalga oshirish, shuningdek, struktura navbatga qo'yilgandan keyin bitta protsessor/yadroda ishlaydigan iplar sonini cheklaydi. Ob'ekt MS Windows-ga xos bo'lib, kiruvchi ulanish so'rovlarini va server dasturiy ta'minotidagi ma'lumotlar qismlarini arxitekturada qayta ishlashga imkon beradi, bunda iplar soni mijozlar sonidan kamroq bo'lishi mumkin (resurs xarajatlari bilan alohida oqim yaratish talabi yo'q). har bir yangi mijoz).

· ERESOURCE. Umumiy yoki eksklyuziv suratga olish semantikasi bilan rekursiv suratga olishni qo‘llab-quvvatlaydigan muteks. Semantika: ob'ekt bepul bo'lishi mumkin yoki umumiy tarzda ixtiyoriy miqdordagi iplar tomonidan qo'lga olinishi yoki faqat bitta ip tomonidan eksklyuziv tarzda olinishi mumkin. Ushbu qoidani buzadigan har qanday suratga olishga urinishlar ob'ekt bo'shatilguncha ipni to'sib qo'yadi, shunda tortib olishga ruxsat beriladi. TryToAcquire kabi operatsiyalar ham mavjud - u hech qachon ipni bloklamaydi, yoki ushlaydi yoki (agar qulf kerak bo'lsa) hech narsa qilmasdan FALSE ni qaytaradi. U Windows yadrosida, ayniqsa fayl tizimlarida qo'llaniladi - masalan, har qanday ochiq disk fayli FCB tuzilishiga mos keladi, unda fayl hajmiga kirishni sinxronlashtirish uchun 2 ta shunday ob'ekt mavjud. Ulardan biri - paging IO resursi - faqat faylni kesish yo'lida saqlanadi va kesish vaqtida keshdan va fayldagi xotira xaritasidan faol kiritish-chiqarish yo'qligini ta'minlaydi.

Yaroqsiz himoya. Windows yadrosidagi yarim hujjatlashtirilgan (qo'ng'iroqlar sarlavhali fayllarda mavjud, lekin hujjatlarda mavjud emas). "O'sish", "kamaytirish" va "kutish" operatsiyalari bilan hisoblagich. Kutish, pasaytirish operatsiyalari hisoblagichni nolga tushirmaguncha ipni bloklaydi. Bundan tashqari, o'sish operatsiyasi muvaffaqiyatsiz bo'lishi mumkin va hozirda faol kutish vaqtining mavjudligi barcha oshirish operatsiyalarining muvaffaqiyatsiz bo'lishiga olib keladi.

Avvalgi xabarlarda CreateThread va boshqa WinAPI-dan foydalangan holda Windows-da multithreading, shuningdek, Linux va boshqa * nix tizimlarida pthreadlar yordamida ko'p ish zarralari haqida so'z bordi. Agar siz C ++ 11 yoki undan keyingi versiyalarda yozayotgan bo'lsangiz, u holda std :: thread va ushbu til standartida kiritilgan boshqa ko'p oqimli primitivlar siz uchun mavjud. Quyida ular bilan qanday ishlash kerakligi ko'rsatilgan. WinAPI va pthreadlardan farqli o'laroq, std :: da yozilgan kod o'zaro platforma hisoblanadi.

Eslatma: Yuqoridagi kod Arch Linux ostida GCC 7.1 va Clang 4.0, Ubuntu 16.04 LTS ostida GCC 5.4 va Clang 3.8, FreeBSD 11 ostida GCC 5.4 va Clang 3.8 va Windows 10 ostida Visual Studio Community 2017 da sinovdan oʻtgan. CMake 38 versiyasidan oldin gapira olmaydi. kompilyator loyiha xususiyatlarida ko'rsatilgan C ++ 17 standartidan foydalanishi kerak. Ubuntu 16.04 da CMake 3.8 qanday o'rnatiladi. Kodni Clang bilan kompilyatsiya qilish uchun libc ++ paketi * nix tizimlariga o'rnatilgan bo'lishi kerak. Arch Linux uchun paket AUR da mavjud. Ubuntu'da libc ++ - dev paketi mavjud, ammo kodni osongina yaratishga to'sqinlik qiladigan muammolarga duch kelishingiz mumkin. Vaqtinchalik yechim StackOverflow da tasvirlangan. FreeBSD-da loyihani kompilyatsiya qilish uchun cmake-modules paketini o'rnatishingiz kerak.

Mutekslar

Quyida savdo va mutekslardan foydalanishning eng oddiy misoli keltirilgan:

#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi

Std :: mutex mtx;
statik int hisoblagichi = 0;


uchun (;;) (
{
std :: lock_guard< std:: mutex >qulflash (mtx);

sindirish;
int ctr_val = ++ hisoblagich;
std :: cout<< "Thread " << tnum << ": counter = " <<
ctr_val<< std:: endl ;
}

}
}

int main () (
std :: vektor< std:: thread >iplar;
uchun (int i = 0; i< 10 ; i++ ) {


}

// const auto & bu yerda ishlata olmayman, chunki .join () const belgilanmagan

thr.join ();
}

Std :: cout<< "Done!" << std:: endl ;
qaytish 0;
}

std :: mutex ning std :: lock_guard ichida RAII idiomasiga ko'ra o'ralganligiga e'tibor bering. Ushbu yondashuv mutexni har qanday holatda, shu jumladan istisnolar tashlanganida, doiradan chiqqanda bo'shatishini ta'minlaydi. O'liklarning oldini olish uchun bir vaqtning o'zida bir nechta mutekslarni olish uchun std :: scoped_lock klassi mavjud. Biroq, u faqat C ++ 17 da paydo bo'lgan va shuning uchun hamma joyda ishlamasligi mumkin. C++ ning oldingi versiyalari uchun funksionallik jihatidan oʻxshash std :: lock shabloni mavjud, garchi u RAII yordamida qulflarni toʻgʻri chiqarish uchun qoʻshimcha kod yozishni talab qiladi.

RWLock

Ko'pincha ob'ektga kirish yozishdan ko'ra tez-tez o'qiladigan vaziyat yuzaga keladi. Bunday holda, odatdagi mutex o'rniga, o'qish-yozish blokirovkasidan foydalanish samaraliroq bo'ladi, ya'ni RWLock. RWLock o'qish uchun bir vaqtning o'zida bir nechta iplar tomonidan yoki yozish uchun faqat bitta ip tomonidan olinishi mumkin. C ++ da RWLock std :: shared_mutex va std :: shared_timed_mutex sinflariga mos keladi:

#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi

// std :: shared_mutex mtx; // GCC 5.4 bilan ishlamaydi
std :: shared_timed_mutex mtx;

statik int hisoblagichi = 0;
statik const int MAX_COUNTER_VAL = 100;

void thread_proc (int tnum) (
uchun (;;) (
{
// std :: shared_lock ga ham qarang
std :: unique_lock< std:: shared_timed_mutex >qulflash (mtx);
agar (hisoblagich == MAX_COUNTER_VAL)
sindirish;
int ctr_val = ++ hisoblagich;
std :: cout<< "Thread " << tnum << ": counter = " <<
ctr_val<< std:: endl ;
}
std :: this_thread :: sleep_for (std :: chrono :: millisekundlar (10));
}
}

int main () (
std :: vektor< std:: thread >iplar;
uchun (int i = 0; i< 10 ; i++ ) {
std :: thread thr (thread_proc, i);
threads.emplace_back (std :: move (thr));
}

uchun (avtomatik va thr: mavzular) (
thr.join ();
}

Std :: cout<< "Done!" << std:: endl ;
qaytish 0;
}

std :: lock_guard bilan o'xshashlik bo'yicha, std :: unique_lock va std :: shared_lock sinflari RWLockni qanday suratga olishni xohlashimizga qarab ishlatiladi. std :: shared_timed_mutex klassi C ++ 14 da paydo bo'ldi va barcha * zamonaviy platformalarda ishlaydi (mobil qurilmalar, o'yin konsollari va boshqalar uchun aytmayman). Std :: shared_mutex dan farqli o'laroq, unda try_lock_for, try_lock_unti va ma'lum vaqt uchun mutexni blokirovka qilishga harakat qiladigan boshqa usullar mavjud. Men std :: shared_mutex std :: shared_timed_mutex dan arzonroq bo'lishi kerakligiga shubha qilaman. Biroq, std :: shared_mutex faqat C ++ 17 da paydo bo'ldi, demak u hamma joyda ham qo'llab-quvvatlanmaydi. Xususan, hali ham keng qo'llaniladigan GCC 5.4 bu haqda bilmaydi.

Thread Mahalliy saqlash

Ba'zan siz global kabi o'zgaruvchini yaratishingiz kerak bo'ladi, lekin uni faqat bitta ip ko'radi. Boshqa iplar ham o'zgaruvchini ko'radi, lekin ular o'zlarining mahalliy ma'nosiga ega. Buning uchun ular Thread Local Storage yoki TLS (Transport Layer Security bilan hech qanday aloqasi yo'q!) ni o'ylab topishdi. Boshqa narsalar qatorida, TLS psevdo-tasodifiy raqamlarni yaratishni sezilarli darajada tezlashtirish uchun ishlatilishi mumkin. C++ da TLS dan foydalanishga misol:

#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi

Std :: mutex io_mtx;
thread_local int counter = 0;
statik const int MAX_COUNTER_VAL = 10;

void thread_proc (int tnum) (
uchun (;;) (
hisoblagich ++;
agar (hisoblagich == MAX_COUNTER_VAL)
sindirish;
{
std :: lock_guard< std:: mutex >qulflash (io_mtx);
std :: cout<< "Thread " << tnum << ": counter = " <<
hisoblagich<< std:: endl ;
}
std :: this_thread :: sleep_for (std :: chrono :: millisekundlar (10));
}
}

int main () (
std :: vektor< std:: thread >iplar;
uchun (int i = 0; i< 10 ; i++ ) {
std :: thread thr (thread_proc, i);
threads.emplace_back (std :: move (thr));
}

uchun (avtomatik va thr: mavzular) (
thr.join ();
}

Std :: cout<< "Done!" << std:: endl ;
qaytish 0;
}

Muteks bu erda faqat chiqishni konsolga sinxronlashtirish uchun ishlatiladi. thread_local o'zgaruvchilarga kirish uchun sinxronizatsiya talab qilinmaydi.

Atom o'zgaruvchilari

Atom o'zgaruvchilari ko'pincha mutekslardan foydalanmasdan oddiy amallarni bajarish uchun ishlatiladi. Misol uchun, bir nechta iplardan hisoblagichni oshirishingiz kerak. Int ni std :: mutexga o'rash o'rniga std :: atomic_int dan foydalanish samaraliroq. C ++ shuningdek, std :: atomic_char, std :: atomic_bool va boshqalarni taklif qiladi. Bloksiz algoritmlar va ma'lumotlar tuzilmalari atom o'zgaruvchilari yordamida ham amalga oshiriladi. Shuni ta'kidlash kerakki, ularni ishlab chiqish va disk raskadrovka qilish juda qiyin va barcha tizimlar qulflangan shunga o'xshash algoritmlar va ma'lumotlar tuzilmalaridan tezroq ishlamaydi.

Kod namunasi:

#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi
#o'z ichiga oladi

statik std :: atomic_int atomik_hisoblagich (0);
statik const int MAX_COUNTER_VAL = 100;

Std :: mutex io_mtx;

void thread_proc (int tnum) (
uchun (;;) (
{
int ctr_val = ++ atomik_hisoblagich;
agar (ctr_val> = MAX_COUNTER_VAL)
sindirish;

{
std :: lock_guard< std:: mutex >qulflash (io_mtx);
std :: cout<< "Thread " << tnum << ": counter = " <<
ctr_val<< std:: endl ;
}
}
std :: this_thread :: sleep_for (std :: chrono :: millisekundlar (10));
}
}

int main () (
std :: vektor< std:: thread >iplar;

int nthreads = std :: thread :: hardware_concurrency ();
agar (nthreads == 0) nthreads = 2;

uchun (int i = 0; i< nthreads; i++ ) {
std :: thread thr (thread_proc, i);
threads.emplace_back (std :: move (thr));
}

uchun (avtomatik va thr: mavzular) (
thr.join ();
}

Std :: cout<< "Done!" << std:: endl ;
qaytish 0;
}

hardware_concurrency protsedurasidan foydalanishga e'tibor bering. U joriy tizimda parallel ravishda ishga tushirilishi mumkin bo'lgan iplar sonining taxminiy qiymatini qaytaradi. Masalan, giper tormozlashni qo'llab-quvvatlaydigan to'rt yadroli protsessorli mashinada protsedura 8 ni qaytaradi. Bundan tashqari, agar baholash muvaffaqiyatsiz bo'lsa yoki protsedura oddiygina amalga oshirilmagan bo'lsa, protsedura nolni qaytarishi mumkin.

Atom o'zgaruvchilari assembler darajasida qanday ishlashi haqida ba'zi ma'lumotlarni olish uchun X86 / x64 uchun asosiy yig'ish ko'rsatmalari uchun Cheat Sheet maqolasiga qarang.

Xulosa

Ko'rib turganimdek, bularning barchasi juda yaxshi ishlaydi. Ya'ni, C ++ da o'zaro platforma ilovalarini yozishda siz WinAPI va pthreads haqida ishonch bilan unutishingiz mumkin. Sof Cda, C11 dan beri platformalararo savdolar ham mavjud. Lekin ular hali ham Visual Studio tomonidan qo'llab-quvvatlanmaydi (men tekshirdim) va hech qachon bo'lishi dargumon. Hech kimga sir emaski, Microsoft o'zining kompilyatorida C tilini qo'llab-quvvatlashni rivojlantirishga qiziqish bildirmaydi, C ++ ga e'tibor qaratishni afzal ko'radi.

Hali ham parda ortida juda ko'p ibtidoiy narsalar mavjud: std :: condition_variable (_har qanday), std: :(shared_) kelajak, std :: contract, std :: sync va boshqalar. Men ularni ko'rib chiqish uchun cppreference.com ni tavsiya qilaman. C ++ Concurrency in Action kitobini o'qish ham mantiqiy bo'lishi mumkin. Ammo men sizni ogohlantirishim kerakki, u endi yangi emas, juda ko'p suvni o'z ichiga oladi va aslida cppreference.com saytidan o'nlab maqolalarni takrorlaydi.

Ushbu eslatma uchun to'liq manba kodi, odatdagidek, GitHub-da. Ko'p oqimli C ++ ilovalarini hozir qanday yozasiz?

Clay Breshears

Kirish

Intelning multithreading amalga oshirish usullari to'rtta asosiy bosqichni o'z ichiga oladi: tahlil qilish, dizayn va amalga oshirish, disk raskadrovka va unumdorlikni sozlash. Bu ketma-ket koddan ko'p tarmoqli dastur yaratish uchun ishlatiladigan yondashuv. Birinchi, uchinchi va to'rtinchi bosqichlarda dasturiy ta'minot bilan ishlash juda keng yoritilgan, ikkinchi bosqichni amalga oshirish bo'yicha ma'lumotlar aniq etarli emas.

Parallel algoritmlar va parallel hisoblashlar bo'yicha ko'plab kitoblar nashr etilgan. Biroq, bu nashrlar asosan xabarlarni uzatish, taqsimlangan xotira tizimlari yoki ba'zan haqiqiy ko'p yadroli platformalar uchun qo'llanilmaydigan nazariy parallel hisoblash modellarini qamrab oladi. Agar siz ko'p qirrali dasturlash bilan jiddiy shug'ullanishga tayyor bo'lsangiz, ehtimol sizga ushbu modellar uchun algoritmlarni ishlab chiqish bo'yicha bilim kerak bo'ladi. Albatta, ushbu modellardan foydalanish ancha cheklangan, shuning uchun ko'plab dasturiy ta'minot ishlab chiqaruvchilari ularni amalda qo'llashlari kerak bo'lishi mumkin.

Ko‘p tarmoqli ilovalarni ishlab chiqish, avvalo, ijodiy faoliyat, shundan keyingina ilmiy faoliyat desak mubolag‘a bo‘lmaydi. Ushbu maqolada siz bir vaqtning o'zida dasturlash amaliyotlari bazasini kengaytirishga yordam beradigan sakkizta oddiy qoidalar haqida bilib olasiz va ilovalaringizni o'tkazish samaradorligini oshirasiz.

Qoida 1. Dastur kodida bajariladigan amallarni bir-biridan mustaqil ravishda tanlang

Parallel ishlov berish faqat bir-biridan mustaqil ravishda bajariladigan ketma-ket koddagi operatsiyalar uchun amal qiladi. Mustaqil harakatlar haqiqiy yagona natijaga olib kelishining yaxshi namunasi - bu uy qurish. Unga ko'plab ixtisoslikdagi ishchilar jalb qilingan: duradgorlar, elektrchilar, suvoqchilar, chilangarlar, tomchilar, bo'yoqchilar, g'isht teruvchilar, bog'bonlar va boshqalar. Albatta, ularning ba'zilari o'z faoliyatini to'xtatmasdan ishga kirisha olmaydi (masalan, devorlar qurilmaguncha tom yopishchilar ish boshlamaydi, agar ular suvoq qilinmasa, rassomlar bu devorlarni bo'yashmaydi). Ammo umuman olganda, qurilishda ishtirok etgan barcha odamlar bir-biridan mustaqil ravishda harakat qilishlarini aytishimiz mumkin.

Yana bir misolni ko'rib chiqaylik - ma'lum filmlar uchun buyurtmalarni qabul qiladigan DVD ijarasi do'konining ish aylanishi. Bu plyonkalarni ombordan qidirayotgan punkt xodimlariga buyurtmalar taqsimlanadi. Tabiiyki, agar ishchilardan biri Odri Xepbern bilan film yozilgan diskni ombordan olsa, bu Arnold Shvartsenegger bilan boshqa jangovar film qidirayotgan boshqa ishchiga hech qanday ta'sir qilmaydi va bundan ham ko'proq ularning hamkasbiga ta'sir qilmaydi. kim "Do'stlar" seriyasining yangi mavsumi bilan disklarni qidirmoqda. Bizning misolimizda, biz stokda plyonkalarning etishmasligi bilan bog'liq barcha muammolar buyurtmalar ijara punktiga kelgunga qadar hal qilinganiga ishonamiz va har qanday buyurtmani qadoqlash va jo'natish boshqalarni qayta ishlashga ta'sir qilmaydi.

Sizning ishingizda, ehtimol, siz parallel emas, balki faqat ma'lum bir ketma-ketlikda qayta ishlanishi mumkin bo'lgan hisob-kitoblarga duch kelasiz, chunki tsiklning turli xil takrorlashlari yoki bosqichlari bir-biriga bog'liq va qat'iy tartibda bajarilishi kerak. Keling, yovvoyi tabiatdan jonli misol keltiraylik. Homilador kiyikni tasavvur qiling. Homilaning tug'ilishi o'rtacha sakkiz oy davom etganligi sababli, bir vaqtning o'zida sakkiz bug'u homilador bo'lsa ham, bir oy ichida loyqa paydo bo'lmaydi. Biroq, bir vaqtning o'zida sakkizta bug'u, agar ularning barchasiga Qorboboning chanasida bog'langan bo'lsa, o'z vazifalarini a'lo darajada bajaradi.

Qoida 2. Tafsilotning past darajasi bilan parallelizmni qo'llang

Ketma-ket dastur kodini parallel qismlarga ajratishning ikkita yondashuvi mavjud: pastdan yuqoriga va yuqoridan pastga. Birinchidan, kodni tahlil qilish bosqichida dasturni bajarish vaqtining muhim qismini egallagan kod segmentlari ("issiq" nuqtalar) aniqlanadi. Ushbu kod segmentlarini parallel ravishda ajratish (agar iloji bo'lsa) maksimal samaradorlikni ta'minlaydi.

Pastdan yuqoriga yondashuv kodning issiq nuqtalarini ko'p bosqichli qayta ishlashni amalga oshiradi. Agar topilgan nuqtalarni parallel bo'linish imkoni bo'lmasa, parallel bo'linish uchun mavjud bo'lgan boshqa segmentlarni aniqlash uchun dastur chaqiruvlari to'plamini ko'rib chiqishingiz kerak va bajarilishi uzoq vaqt talab etiladi. Aytaylik, siz grafiklarni siqish uchun dastur ustida ishlayapsiz. Siqish tasvirning alohida segmentlarini qayta ishlovchi bir nechta mustaqil parallel oqimlar yordamida amalga oshirilishi mumkin. Biroq, agar siz ko'p tarmoqli "qaynoq nuqtalarni" amalga oshirishga muvaffaq bo'lsangiz ham, qo'ng'iroqlar to'plamini tahlil qilishni e'tiborsiz qoldirmang, buning natijasida dastur kodining yuqori darajasida parallel bo'linish uchun mavjud bo'lgan segmentlarni topishingiz mumkin. Shunday qilib, siz parallel ishlov berishning granularligini oshirishingiz mumkin.

Yuqoridan pastga yondashuvda dastur kodining ishi tahlil qilinadi va uning alohida segmentlari ajratib ko'rsatiladi, ularning bajarilishi butun vazifani bajarishga olib keladi. Agar asosiy kod segmentlarining aniq mustaqilligi bo'lmasa, mustaqil hisoblarni topish uchun ularning tarkibiy qismlarini tahlil qiling. Dastur kodini tahlil qilib, siz eng ko'p CPU vaqtini sarflaydigan kod modullarini aniqlashingiz mumkin. Keling, videoni kodlash ilovasida ipni qanday amalga oshirishni ko'rib chiqaylik. Parallel ishlov berish eng past darajada - bitta freymning mustaqil piksellari uchun yoki undan yuqori darajada - boshqa guruhlardan mustaqil ravishda qayta ishlanishi mumkin bo'lgan freymlar guruhlari uchun amalga oshirilishi mumkin. Agar dastur bir vaqtning o'zida bir nechta video fayllarni qayta ishlash uchun yozilayotgan bo'lsa, bu darajadagi parallel bo'linish yanada osonroq bo'lishi mumkin va tafsilot eng past bo'ladi.

Parallel hisoblashning granularligi iplar o'rtasida sinxronizatsiya qilishdan oldin bajarilishi kerak bo'lgan hisoblash miqdorini bildiradi. Boshqacha qilib aytganda, sinxronizatsiya qanchalik tez-tez sodir bo'lmasa, granularlik shunchalik past bo'ladi. Yupqa zarrachali iplarni o'tkazish hisob-kitoblari tizimning yivlarni o'tkazishga qo'shimcha xarajatlari ushbu iplar tomonidan bajarilgan foydali hisoblardan ustun bo'lishiga olib kelishi mumkin. Bir xil miqdordagi hisoblash bilan iplar sonining ko'payishi ishlov berish jarayonini murakkablashtiradi. Past darajali ko'p ish zarrachalari tizimning kechikishini kamroq joriy qiladi va kengaytirilishi uchun ko'proq potentsialga ega, bunga qo'shimcha iplar yordamida erishish mumkin. Past granularlik parallel ishlov berishni amalga oshirish uchun yuqoridan pastga yondashuvni va qo'ng'iroqlar to'plamida yuqori darajada ipni ishlatish tavsiya etiladi.

3-qoida. Yadrolar soni ortib borishi bilan ishlashni yaxshilash uchun kodingizda miqyoslilikni yarating.

Yaqinda bozorda ikki yadroli protsessorlarga qo'shimcha ravishda to'rt yadroli protsessorlar paydo bo'ldi. Bundan tashqari, Intel sekundiga trillion suzuvchi nuqta operatsiyalarini bajarishga qodir 80 yadroli protsessorni allaqachon e'lon qildi. Protsessorlardagi yadrolar soni vaqt o'tishi bilan o'sib borishi sababli, sizning kodingiz kengaytirilishi uchun etarli potentsialga ega bo'lishi kerak. Scalability - bu tizim resurslarining ko'payishi (yadrolar soni, xotira hajmi, avtobus chastotasi va boshqalar) yoki ma'lumotlar hajmining ko'payishi kabi o'zgarishlarga dasturning adekvat javob berish qobiliyatini baholash mumkin bo'lgan parametr. Kelajakdagi protsessorlardagi yadrolar soni ortib borishi bilan tizim resurslarini oshirish orqali unumdorlikni oshiradigan kengaytiriladigan kodni yozing.

C. Northecote Parkinson qonunlaridan birini ifodalash uchun, biz aytishimiz mumkinki, "ma'lumotlarni qayta ishlash barcha mavjud tizim resurslarini oladi". Bu shuni anglatadiki, hisoblash resurslari ortib borishi bilan (masalan, yadrolar soni), ularning barchasi ma'lumotlarni qayta ishlash uchun ishlatilishi mumkin. Keling, yuqorida muhokama qilingan videoni siqish ilovasiga qaytaylik. Protsessorga qo'shimcha yadrolarning qo'shilishi qayta ishlangan kadrlar hajmiga ta'sir qilishi dargumon - buning o'rniga, kadrni qayta ishlovchi iplar soni ortadi, bu esa oqimdagi piksellar sonining kamayishiga olib keladi. Natijada, qo'shimcha oqimlarni tashkil etish hisobiga xizmat ko'rsatish ma'lumotlarining hajmi oshadi va parallellik granularlik darajasi pasayadi. Yana bir ehtimoliy stsenariy - kodlanishi kerak bo'lgan video fayllar hajmi yoki sonining ko'payishi. Bunday holda, kattaroq (yoki qo'shimcha) video fayllarni qayta ishlovchi qo'shimcha oqimlarni tashkil etish ishning butun hajmini to'g'ridan-to'g'ri o'sish sodir bo'lgan bosqichda bo'lish imkonini beradi. O'z navbatida, bunday imkoniyatlarga ega bo'lgan dastur kengaytirilishi uchun yuqori salohiyatga ega bo'ladi.

Ma'lumotlarning parchalanishidan foydalangan holda parallel ishlov berishni loyihalash va amalga oshirish funktsional dekompozitsiyadan foydalanishga nisbatan kengaytirilgan miqyosni ta'minlaydi. Dastur kodidagi mustaqil funktsiyalar soni ko'pincha cheklangan va dasturni bajarish jarayonida o'zgarmaydi. Har bir mustaqil funktsiyaga alohida ip (va shunga mos ravishda protsessor yadrosi) ajratilganligi sababli, yadrolar sonining ko'payishi bilan qo'shimcha ravishda tashkil etilgan iplar ishlashning oshishiga olib kelmaydi. Shunday qilib, ma'lumotlarni parchalash bilan parallel bo'linish modellari qayta ishlangan ma'lumotlar miqdori protsessor yadrolari soni ortib borishi sababli dasturning miqyoslanishi uchun ortib borayotgan potentsialni ta'minlaydi.

Dastur kodi mustaqil funktsiyalarni o'tkazayotgan bo'lsa ham, kirish yuki ortganda ishga tushiriladigan qo'shimcha iplardan foydalanish mumkin. Keling, yuqorida muhokama qilingan uy qurish misoliga qaytaylik. Qurilishning o'ziga xos maqsadi cheklangan miqdordagi mustaqil vazifalarni bajarishdir. Biroq, agar sizga ikki barobar ko'p qavat qurish buyurilgan bo'lsa, ehtimol siz ba'zi mutaxassisliklar bo'yicha qo'shimcha ishchilarni yollashni xohlaysiz (rassomlar, tom yopishchilar, chilangarlar va boshqalar). Shunday qilib, ish yukining ortishi natijasida ma'lumotlarning parchalanishiga moslasha oladigan ilovalarni ishlab chiqishingiz kerak. Agar sizning kodingiz funktsional dekompozitsiyani amalga oshirsa, protsessor yadrolari soni ortishi bilan qo'shimcha oqimlarni tashkil qilishni o'ylab ko'ring.

4-qoida. Tarmoqli xavfsiz kutubxonalardan foydalaning

Agar sizga kodingizdagi ma'lumotlarning faol nuqtalarini boshqarish uchun kutubxona kerak bo'lsa, o'z kodingiz o'rniga tayyor funktsiyalardan foydalanishni o'ylab ko'ring. Muxtasar qilib aytganda, funktsiyalari allaqachon kutubxonadan optimallashtirilgan protseduralarda taqdim etilgan kod segmentlarini ishlab chiqish orqali g'ildirakni qayta ixtiro qilishga urinmang. Ko'pgina kutubxonalar, jumladan Intel® Math Kernel Library (Intel® MKL) va Intel® Integrated Performance Primitives (Intel® IPP) allaqachon ko'p yadroli protsessorlar uchun optimallashtirilgan ko'p oqimli funksiyalarni o'z ichiga oladi.

Shuni ta'kidlash kerakki, ko'p tarmoqli kutubxonalardan protseduralardan foydalanganda, u yoki bu kutubxonani chaqirish iplarning normal ishlashiga ta'sir qilmasligiga ishonch hosil qilishingiz kerak. Ya'ni, agar protsedura qo'ng'iroqlari ikki xil ipdan qilingan bo'lsa, har bir qo'ng'iroqdan to'g'ri natijalar qaytarilishi kerak. Agar protseduralar umumiy kutubxona o'zgaruvchilariga murojaat qilsa va ularni yangilasa, ma'lumotlar poygasi paydo bo'lishi mumkin, bu esa hisoblash natijalarining ishonchliligiga salbiy ta'sir qiladi. Mavzular bilan to'g'ri ishlash uchun kutubxona protsedurasi yangi sifatida qo'shiladi (ya'ni u mahalliy o'zgaruvchilardan boshqa hech narsani yangilamaydi) yoki umumiy resurslarga kirishni himoya qilish uchun sinxronlashtiriladi. Xulosa: dastur kodida uchinchi tomon kutubxonasidan foydalanishdan oldin, oqimlar bilan to'g'ri ishlashiga ishonch hosil qilish uchun unga biriktirilgan hujjatlarni o'qing.

5-qoida. Tegishli ko'p tarmoqli modeldan foydalaning

Aytaylik, ko'p tarmoqli kutubxonalarning funktsiyalari barcha mos kod segmentlarini parallel bo'lish uchun etarli emas va siz iplarni tashkil qilish haqida o'ylashingiz kerak edi. Agar OpenMP kutubxonasi sizga kerak bo'lgan barcha funksiyalarni o'z ichiga olgan bo'lsa, o'zingizning (qiyin) ip strukturangizni yaratishga shoshilmang.

Aniq multithreadingning salbiy tomoni aniq ipni boshqarishning mumkin emasligi.

Agar sizga faqat resursni talab qiladigan pastadirlarni parallel ravishda ajratish kerak bo'lsa yoki aniq iplar taqdim etadigan qo'shimcha moslashuvchanlik siz uchun ikkinchi darajali bo'lsa, unda bu holda qo'shimcha ishni bajarish mantiqiy emas. Ko'p ish zarralarini amalga oshirish qanchalik murakkab bo'lsa, koddagi xatolar ehtimoli shunchalik yuqori bo'ladi va uni keyingi qayta ko'rib chiqish shunchalik qiyin bo'ladi.

OpenMP kutubxonasi ma'lumotlarning parchalanishiga qaratilgan va ayniqsa katta hajmdagi ma'lumotlar bilan ishlaydigan halqalarni o'tkazish uchun juda mos keladi. Ba'zi ilovalar uchun faqat ma'lumotlarni parchalash qo'llanilishiga qaramay, qo'shimcha talablarni (masalan, ish beruvchi yoki mijozning) hisobga olish kerak, ularga ko'ra OpenMP-dan foydalanish qabul qilinishi mumkin emas va aniq ma'lumotlardan foydalangan holda ko'p ishlamalarni amalga oshirish qoladi. usullari. Bunday holda, OpenMP potentsial ishlash o'sishini, miqyoslanishini va keyinchalik aniq ko'p ish zarralari orqali kodni bo'lish uchun kerak bo'ladigan taxminiy harakatlarni baholash uchun dastlabki tirqish uchun ishlatilishi mumkin.

Qoida 6. Dastur kodining natijasi parallel iplarni bajarish ketma-ketligiga bog'liq bo'lmasligi kerak.

Ketma-ket dastur kodi uchun har qanday boshqa ifodadan keyin bajariladigan ifodani aniqlash kifoya. Ko'p oqimli kodda iplarni bajarish tartibi aniqlanmagan va operatsion tizim rejalashtiruvchisining ko'rsatmalariga bog'liq. To'g'risini aytganda, operatsiyani bajarish uchun ishga tushiriladigan iplar ketma-ketligini oldindan aytish yoki keyinchalik rejalashtiruvchi tomonidan qaysi ipni ishga tushirishni aniqlash deyarli mumkin emas. Prognozlash, birinchi navbatda, dasturning kechikish vaqtini kamaytirish uchun ishlatiladi, ayniqsa, tashkil etilgan iplar sonidan kamroq yadroli protsessorli platformada ishlaganda. Agar ip keshga yozilmagan hududga kirish kerakligi yoki kiritish-chiqarish so'rovini bajarishi kerakligi sababli bloklangan bo'lsa, rejalashtiruvchi uni to'xtatib qo'yadi va ipni boshlashga tayyor holda boshlaydi.

Ma'lumotlar poygasi holatlari ipni bajarishni rejalashtirishdagi noaniqlikning bevosita natijasidir. Ba'zi bir ish zarrachalari umumiy o'zgaruvchining qiymatini boshqa oqim o'qishdan oldin o'zgartiradi deb taxmin qilish noto'g'ri bo'lishi mumkin. Omad tilaymiz, ma'lum bir platforma uchun iplarni bajarish tartibi ilovaning barcha ishga tushirilishida bir xil bo'lib qoladi. Biroq, tizim holatidagi eng kichik o'zgarishlar (masalan, qattiq diskdagi ma'lumotlarning joylashuvi, xotira tezligi yoki hatto AC quvvat manbai tarmog'ining nominal chastotasidan og'ish) boshqa tartibni keltirib chiqarishi mumkin. iplarning bajarilishi. Shunday qilib, faqat ma'lum bir qator ketma-ketligi bilan to'g'ri ishlaydigan dastur kodi uchun "ma'lumotlar poygasi" holatlari va blokirovkalar bilan bog'liq muammolar bo'lishi mumkin.

Ishlashning ortishi nuqtai nazaridan, iplarni bajarish tartibini cheklamaslik afzalroqdir. Oqimlarni bajarishning qat'iy ketma-ketligiga faqat oldindan belgilangan mezon bilan belgilanadigan favqulodda holatlarda ruxsat beriladi. Bunday vaziyat yuzaga kelganda, iplar taqdim etilgan sinxronizatsiya mexanizmlari tomonidan belgilangan tartibda ishga tushiriladi. Misol uchun, ikki do'st stol ustiga yoyilgan gazetani o'qiyotganini tasavvur qiling. Birinchidan, ular turli xil tezlikda o'qishlari mumkin, ikkinchidan, ular turli maqolalarni o'qishlari mumkin. Bu yerda esa gazetaning tarqalishini kim birinchi bo‘lib o‘qishining ahamiyati yo‘q – har holda, u sahifani ochishdan oldin do‘stini kutishiga to‘g‘ri keladi. Shu bilan birga, maqolalarni o'qish vaqti va tartibi bo'yicha hech qanday cheklovlar yo'q - do'stlar istalgan tezlikda o'qiydilar va ular orasidagi sinxronizatsiya sahifani o'girganda darhol sodir bo'ladi.

7-qoida. Mahalliy oqim xotirasidan foydalaning. Zarur bo'lganda ma'lum ma'lumotlar sohalariga qulflarni tayinlang

Sinxronizatsiya tizimdagi yukni muqarrar ravishda oshiradi, bu hech qanday tarzda parallel hisoblash natijalarini olish jarayonini tezlashtirmaydi, lekin ularning to'g'riligini ta'minlaydi. Ha, sinxronizatsiya zarur, lekin uni ortiqcha ishlatmaslik kerak. Sinxronizatsiyani minimallashtirish uchun oqimlarni yoki ajratilgan xotira maydonlarini mahalliy saqlash (masalan, tegishli oqimlarning identifikatorlari bilan belgilangan massiv elementlari) ishlatiladi.

Vaqtinchalik o'zgaruvchilarni turli mavzular bo'yicha almashish zarurati kam uchraydi. Bunday o'zgaruvchilar e'lon qilinishi yoki har bir oqim uchun mahalliy sifatida ajratilishi kerak. Qiymatlari iplarni bajarishning oraliq natijalari bo'lgan o'zgaruvchilar ham tegishli iplar uchun mahalliy deb e'lon qilinishi kerak. Ushbu oraliq natijalarni umumiy xotira sohasida jamlash uchun sinxronizatsiya talab qilinadi. Tizimdagi potentsial stressni minimallashtirish uchun ushbu umumiy hududni iloji boricha kamroq yangilash afzalroqdir. Aniq ko'p tarmoqli usullari uchun kodning bir ko'p tarmoqli segmenti bajarilishining boshlanishidan keyingi segment boshlanishigacha (yoki ko'p tarmoqli funksiyaga bitta qo'ng'iroqni qayta ishlash paytida) mahalliy ma'lumotlarning yaxlitligini ta'minlaydigan mahalliy saqlash API'lari mavjud. xuddi shu funktsiyaning keyingi bajarilishi).

Agar oqimlarni mahalliy saqlash imkoni bo'lmasa, umumiy resurslarga kirish turli xil ob'ektlar, masalan, qulflar yordamida sinxronlashtiriladi. Bunday holda, ma'lum ma'lumotlar bloklariga qulflarni to'g'ri belgilash muhimdir, agar blokirovkalar soni ma'lumotlar bloklari soniga teng bo'lsa, buni qilish eng oson. Xotiraning bir nechta sohalariga kirishni sinxronlashtiradigan yagona qulflash mexanizmi faqat ushbu sohalarning barchasi doimiy ravishda dastur kodining bir xil muhim qismida joylashganda qo'llaniladi.

Agar siz katta hajmdagi ma'lumotlarga, masalan, 10 000 elementli massivga kirishni sinxronlashtirishingiz kerak bo'lsa, nima qilish kerak? Butun massiv uchun bitta qulfni ta'minlash, albatta, ilovadagi qiyinchilikdir. Haqiqatan ham har bir element uchun qulflashni alohida tashkil qilishingiz kerakmi? Keyin, agar 32 yoki 64 ta parallel iplar ma'lumotlarga kirsa ham, siz juda katta xotira maydoniga kirish mojarolarini oldini olishingiz kerak bo'ladi va bunday ziddiyatlarning ehtimoli 1% ni tashkil qiladi. Yaxshiyamki, "modulo qulflari" deb ataladigan bir xil oltin o'rtacha mavjud. Agar N modulli blokdan foydalanilsa, ularning har biri umumiy ma'lumotlar maydonining N-qismiga kirishni sinxronlashtiradi. Misol uchun, agar ikkita shunday qulf tashkil etilsa, ulardan biri massivning juft elementlariga, ikkinchisi esa toq elementlarga kirishni oldini oladi. Bunday holda, iplar kerakli elementga murojaat qilib, uning paritetini aniqlaydi va tegishli qulfni o'rnatadi. Bloklash moduli soni iplar sonini va bir vaqtning o'zida bir xil xotira maydoniga bir nechta iplarning kirish ehtimolini hisobga olgan holda tanlanadi.

E'tibor bering, bir vaqtning o'zida bir nechta qulflash mexanizmlaridan foydalanish bitta xotira maydoniga kirishni sinxronlashtirishga yo'l qo'yilmaydi. Segal qonunini eslaylik: “Birgina soati bor odam soat necha ekanligini aniq biladi. Bir nechta soati bor odam hech narsaga ishonchi komil emas ». Faraz qilaylik, ikki xil qulf o'zgaruvchiga kirishni nazorat qiladi. Bunday holda, birinchi qulf kodning bir segmenti tomonidan, ikkinchisi esa boshqa segment tomonidan ishlatilishi mumkin. Keyin ushbu segmentlarni bajaruvchi iplar bir vaqtning o'zida foydalanayotgan umumiy ma'lumotlar uchun poyga holatida bo'ladi.

8-qoida. Ko'p oqimni amalga oshirish uchun kerak bo'lsa, dasturiy ta'minot algoritmini o'zgartiring

Ilovalarning ketma-ket va parallel ishlashini baholash mezoni - bu bajarilish vaqti. Algoritmni baholash uchun asimptotik tartib mos keladi. Ushbu nazariy ko'rsatkich deyarli har doim dasturning ishlashini baholash uchun foydalidir. Ya'ni, boshqa barcha narsalar teng bo'lsa, o'sish tezligi O (n log n) (tezkor) bo'lgan dastur O (n2) o'sish tezligiga ega bo'lgan dasturga qaraganda tezroq ishlaydi (tanlangan tartib), garchi bularning natijalari ilovalar bir xil.

Amalga oshirishning asimptotik tartibi qanchalik yaxshi bo'lsa, parallel dastur shunchalik tez ishlaydi. Biroq, hatto eng samarali ketma-ketlik algoritmini ham har doim ham parallel oqimlarga bo'lish mumkin emas. Agar dasturning faol nuqtasini ajratish juda qiyin bo'lsa va issiq nuqta qo'ng'iroqlari to'plamining yuqori darajasida ko'p mavzuni o'tkazishning imkoni bo'lmasa, avval siz asl nusxadan ajratish osonroq bo'lgan boshqa ketma-ket algoritmdan foydalanishni o'ylab ko'rishingiz kerak. Albatta, kodingizni o'tkazish uchun tayyorlashning boshqa usullari mavjud.

Oxirgi bayonotning misoli sifatida ikkita kvadrat matritsani ko'paytirishni ko'rib chiqing. Strassen algoritmi eng yaxshi asimptotik bajarilish tartiblaridan biriga ega: O (n2.81), bu oddiy uchli ichki halqa algoritmining O (n3) tartibidan ancha yaxshi. Strassen algoritmiga ko'ra, har bir matritsa to'rtta submatritsaga bo'linadi, shundan so'ng n / 2 × n / 2 submatritsalarni ko'paytirish uchun ettita rekursiv qo'ng'iroq qilinadi. Rekursiv qo'ng'iroqlarni parallellashtirish uchun siz belgilangan o'lchamga yetguncha submatritsalarni ettita mustaqil ko'paytirishni ketma-ket bajaradigan yangi ip yaratishingiz mumkin. Bunday holda, iplar soni eksponent ravishda o'sib boradi va har bir yangi hosil bo'lgan ip tomonidan bajariladigan hisob-kitoblarning granularligi submatritsalar hajmining kamayishi bilan ortadi. Keling, yana bir variantni ko'rib chiqaylik - bir vaqtning o'zida ishlaydigan ettita ipdan iborat hovuzni tashkil qilish va submatritsalarni bitta ko'paytirishni amalga oshirish. Mavzular pulining tugatilgandan so'ng, Strassen usuli submatritsalarni ko'paytirish uchun rekursiv chaqiriladi (dastur kodining ketma-ket versiyasida bo'lgani kabi). Agar bunday dastur bilan ishlaydigan tizim sakkizdan ortiq protsessor yadrolariga ega bo'lsa, ularning ba'zilari ishlamay qoladi.

Matritsani ko'paytirish algoritmini ichki uchlik sikl yordamida parallellashtirish ancha oson. Bunday holda, ma'lumotlarning parchalanishi qo'llaniladi, unda matritsalar satrlarga, ustunlarga yoki submatritsalarga bo'linadi va iplarning har biri ma'lum hisoblarni amalga oshiradi. Bunday algoritmni amalga oshirish tsiklning ma'lum bir darajasiga kiritilgan OpenMP pragmalari yordamida yoki matritsa bo'linishini amalga oshiradigan iplarni aniq tartibga solish orqali amalga oshiriladi. Ushbu oddiyroq ketma-ket algoritmni amalga oshirish, ko'p bosqichli Strassen algoritmini amalga oshirish bilan solishtirganda, dastur kodida kamroq o'zgartirishlarni talab qiladi.

Shunday qilib, endi siz ketma-ket kodni parallelga samarali o'tkazish uchun sakkiz oddiy qoidani bilasiz. Ushbu ko'rsatmalarga rioya qilish orqali siz ishonchliligi, optimal ishlashi va kamroq qiyinchiliklarga ega bo'lgan ko'p bosqichli echimlarni sezilarli darajada tezroq yaratishingiz mumkin bo'ladi.

Ko'p bosqichli dasturlash darsliklari veb-sahifasiga qaytish uchun bu yerga o'ting

Andrey Kolesov

Microsoft .NET Framework uchun ko'p bosqichli ilovalarni yaratish tamoyillarini o'rganishni boshlash uchun, keling, oldindan band qilaylik: barcha misollar Visual Basic .NET da berilgan bo'lsa-da, bunday dasturlarni yaratish metodologiyasi odatda qo'llab-quvvatlaydigan barcha dasturlash tillari uchun bir xil. .NET, shu jumladan C #. VB ko'p tarmoqli ilovalarni yaratish texnologiyasini ko'rsatish uchun tanlangan, chunki bu vositaning oldingi versiyalari bunday imkoniyatni bermagan.

Ehtiyot bo'ling: Visual Basic .NET BUNI ham qila oladi!

Ma'lumki, Visual Basic (6.0 versiyasigacha va shu jumladan) ilgari hech qachon ko'p bosqichli dasturiy ta'minot komponentlarini (EXE, ActiveX DLL va OCX) yaratishga ruxsat bermagan. Esda tutingki, MAQOMOTI arxitekturasi uchta turli tishli modellarni o'z ichiga oladi: bitta ipli, bitta ipli kvartira (STA) va ko'p tishli kvartira. VB 6.0 birinchi ikki turdagi dasturlarni yaratish imkonini beradi. STA versiyasi psevdo-multithreading rejimini ta'minlaydi - bir nechta iplar haqiqatan ham parallel ishlaydi, lekin shu bilan birga ularning har birining dastur kodi unga tashqaridan kirishdan himoyalangan (xususan, iplar umumiy resurslardan foydalana olmaydi).

Visual Basic .NET endi o'zining mahalliy ko'rinishida bepul ish zarralarini amalga oshirishi mumkin. Aniqrog'i, .NET da bu rejim umumiy sinf kutubxonalari Class Library va Common Language Runtime darajasida qo'llab-quvvatlanadi. Natijada, VB.NET boshqa .NET dasturlash tillari bilan birga ushbu imkoniyatlardan foydalanish imkoniyatiga ega bo'ldi.

Bir vaqtlar VB dasturchilar hamjamiyati ushbu tilning kelajakdagi ko'plab yangiliklaridan noroziligini bildirgan holda, vositaning yangi versiyasi yordamida ko'p oqimli dasturlarni yaratish mumkinligi haqidagi xabarga katta ma'qullash bilan munosabatda bo'lishdi (qarang: "Kutish. Visual Studio .NET", "BYTE / Rossiya "No 1/2001). Biroq, ko'plab ekspertlar ushbu yangilikka nisbatan ancha vazminlik bilan baho berishdi. Masalan, taniqli dasturchi va VB dasturchilari uchun ko'plab kitoblar muallifi Den Applemanning fikri: texnologik omillardan ko'ra insoniy sabablarga ko'ra ... Men VB.NET da multithreadingdan qo'rqaman, chunki VB dasturchilari odatda bunday qilmaydi. ko'p bosqichli ilovalarni loyihalash va tuzatish tajribasiga ega.

Darhaqiqat, boshqa past darajadagi dasturlash vositalari (masalan, bir xil Win API-lari) singari, bepul ko'p ish zarralari, bir tomondan, yuqori samarali kengaytiriladigan echimlarni yaratish uchun ko'proq imkoniyatlarni taqdim etsa, boshqa tomondan, u yuqori talablarni qo'yadi. ishlab chiquvchilarning malakasi. Bundan tashqari, bu erda muammo ko'p bosqichli dasturda xatolarni izlash juda qiyin ekanligi bilan yanada og'irlashadi, chunki ular ko'pincha tasodifiy ravishda, parallel hisoblash jarayonlarining aniq kesishishi natijasida paydo bo'ladi (ko'pincha bunday xatolarni takrorlash mumkin emas) yana bir vaziyat). Shuning uchun dasturlarni takroriy ishga tushirish ko'rinishidagi an'anaviy disk raskadrovka usullari odatda bu holatda yordam bermaydi. Ko'p ish zarralarini xavfsiz ishlatishning yagona yo'li "yaxshi dasturlash" ning barcha klassik tamoyillariga rioya qilgan holda ilovangizni yaxshi loyihalashdir.

VB dasturchilari bilan bog'liq muammo shundaki, ularning ko'pchiligi juda tajribali mutaxassislar bo'lsalar va ko'p qirrali ishlashning tuzoqlarini yaxshi bilishsalar ham, VB6 dan foydalanish ularning hushyorligini susaytirishi mumkin. Axir, VB-ni cheklovlarni ayblab, biz ba'zida ko'plab cheklovlar ushbu vositaning takomillashtirilgan xavfsizlik xususiyatlari bilan aniqlanganligini unutamiz, bu esa ishlab chiquvchi xatolarining oldini oladi yoki yo'q qiladi. Masalan, VB6 avtomatik ravishda har bir ish zarrachasi uchun barcha global o'zgaruvchilarning alohida nusxasini yaratadi va shu bilan ular o'rtasida yuzaga kelishi mumkin bo'lgan ziddiyatlarning oldini oladi. VB.NET-da bunday muammolar butunlay dasturchining yelkasiga o'tadi. Shuni ham yodda tutish kerakki, bitta ipli o'rniga ko'p bosqichli modeldan foydalanish har doim ham dastur samaradorligini oshirishga olib kelmaydi, unumdorlik hatto pasayishi mumkin (hatto ko'p protsessorli tizimlarda ham!).

Biroq, yuqorida aytilganlarning barchasi multithreading bilan aralashmaslik uchun maslahat sifatida qabul qilinmasligi kerak. Siz shunchaki bunday rejimlardan qachon foydalanishga arziydiganligi haqida yaxshi tasavvurga ega bo'lishingiz va yanada kuchliroq ishlab chiqish vositasi har doim dasturchining malakasiga yuqori talablarni qo'yishini tushunishingiz kerak.

VB6 da parallel ishlov berish

Albatta, VB6 yordamida psevdoparallel ma'lumotlarni qayta ishlashni tashkil qilish mumkin edi, lekin bu imkoniyatlar juda cheklangan edi. Misol uchun, bir necha yil oldin men dasturning bajarilishini ma'lum soniyalar uchun to'xtatib turadigan protsedurani yozishim kerak edi (tegishli SLEEP bayonoti Microsoft Basic / DOS-da mavjud edi). Uni o'zingiz quyidagi oddiy pastki dastur sifatida amalga oshirish oson:

Uning ishlashini, masalan, formadagi tugmani bosish uchun quyidagi kod yordamida osongina tekshirish mumkin:

VB6 da ushbu muammoni hal qilish uchun SleepVB protsedurasining Do ... Loop ichida boshqaruvni operatsion tizimga o'tkazuvchi va ushbu VB ilovasidagi ochiq shakllar sonini qaytaruvchi DoEvents funksiyasiga qo'ng'iroqni izohdan chiqarish kerak. Ammo shuni yodda tutingki, "Yana bir salom!" Xabari bo'lgan oynani ko'rsatish, o'z navbatida, butun dasturning, shu jumladan SleepVB protsedurasining bajarilishini bloklaydi.

Global o'zgaruvchilarni bayroqlar sifatida ishlatish orqali siz ishlayotgan SleepVB protsedurasi g'ayritabiiy tarzda tugashiga ishonch hosil qilishingiz mumkin. Bu, o'z navbatida, protsessor resurslarini to'liq egallagan hisoblash jarayonining eng oddiy misolidir. Ammo agar siz foydali hisob-kitoblarni amalga oshirmoqchi bo'lsangiz (va bo'sh tsiklda aylanmasangiz), DoEvent funktsiyasiga qo'ng'iroq qilish juda uzoq vaqt talab qilishini yodda tutishingiz kerak, shuning uchun buni juda katta vaqt oralig'ida qilish kerak.

VB6-da parallel hisoblash uchun cheklangan yordamni ko'rish uchun DoEvents funksiyasiga qo'ng'iroqni teg chiqishi bilan almashtiring:

Label1. Caption = Taymer

Bunday holda, nafaqat Command2 tugmasi ishga tushmaydi, balki 5 soniya ichida ham yorliqning mazmuni o'zgarmaydi.

Boshqa tajriba uchun Buyruq2 kodiga kutish qo'ng'irog'ini qo'shing (bu SleepVB protsedurasi qayta kiritilganligi sababli amalga oshirilishi mumkin):

Private Sub Command2_Click () SleepVB ga qo'ng'iroq qiling (5) MsgBox "Yana salom!" End Sub

Keyin dasturni ishga tushiring va Buyruq1-ni bosing va 2-3 soniyadan keyin - Buyruq2-ni bosing. Birinchi paydo bo'ladigan xabar "Yana salom!" Garchi jarayon keyinroq boshlangan bo'lsa ham. Buning sababi shundaki, DoEvents funksiyasi faqat vizual tasvirlardagi hodisalarni tekshiradi, boshqa hisoblash iplari mavjudligini emas. Bundan tashqari, VB ilovasi aslida bitta ish zarrachasida ishlaydi, shuning uchun boshqaruv oxirgi boshlangan voqea protsedurasiga qaytdi.

.NET Thread Control

Ko'p tarmoqli .NET ilovalarini yaratish System.Threading nomlar maydonida tasvirlangan .NET Framework tayanch sinflari guruhidan foydalanishga tayanadi. Bu holda asosiy rol Thread sinfiga tegishli bo'lib, uning yordamida iplarni boshqarish bo'yicha deyarli barcha operatsiyalar bajariladi. Shu nuqtadan boshlab, iplar bilan ishlash haqida aytilganlarning barchasi .NET dagi barcha dasturlash vositalariga, jumladan C # ga ham tegishli.

Parallel oqimlarni yaratish bilan birinchi tanishish uchun biz Windows dasturini forma bilan yaratamiz, unda biz ButtonStart va ButtonAbort tugmachalarini joylashtiramiz va quyidagi kodni yozamiz:

Darhol men sizning e'tiboringizni uchta jihatga qaratmoqchiman. Birinchidan, Import kalit so'zlari nomlar maydoni orqali bu erda tasvirlangan sinflarning qisqartirilgan nomlariga murojaat qilish uchun ishlatiladi. Men dastur matniga qo'llanilishi mumkin bo'lgan uzun nom maydoni nomining (VB = Microsoft.VisualBasic) qisqartirilgan ekvivalentini tavsiflash uchun Importning yana bir ishlatilishini alohida keltirdim. Bunday holda siz Timer obyekti qaysi nom maydoniga tegishli ekanligini darhol ko'rishingiz mumkin.

Ikkinchidan, men yozgan kodni shakl dizayneri tomonidan avtomatik ravishda yaratilgan koddan vizual ravishda ajratish uchun mantiqiy qavslardan foydalandim #Region (ikkinchisi bu erda ko'rsatilmagan).

Uchinchidan, bu holatda muhim bo'lmagan narsalar bilan chalg'imaslik uchun hodisa protseduralarining kirish parametrlarining tavsiflari maxsus olib tashlandi (bu kelajakda ba'zan amalga oshiriladi).

Ilovani ishga tushiring va ButtonStart tugmasini bosing. Belgilangan vaqt oralig'ida tsiklda kutish jarayoni boshlandi va bu holda (VB6 bilan misoldan farqli o'laroq) - mustaqil ipda. Buni ko'rish oson - shaklning barcha vizual elementlariga kirish mumkin. Masalan, ButtonAbort tugmasini bosish orqali Abort usuli yordamida jarayonni bekor qilishingiz mumkin (lekin tizimni Yopish tugmasi yordamida formani yopish protsedurani bekor qilmaydi!). Jarayonning dinamikasi ravshan bo'lishi uchun siz shaklga yorliq qo'yishingiz va joriy vaqtning chiqishini SleepVBNET protsedurasining kutish davriga qo'shishingiz mumkin:

Label1.Text = _ "Hozirgi vaqt =" & VB.TimeOfDay

SleepVBNET protsedurasining bajarilishi (bu holda allaqachon yangi ob'ektning usuli hisoblanadi) agar siz ButtonStart kodiga ip boshlanganidan keyin hisob-kitoblarning boshlanishi haqidagi xabar oynasi ekranini qo'shsangiz ham davom etadi (1-rasm). ).

Keyinchalik murakkab variant - bu sinf sifatida oqim

Mavzular bilan keyingi tajribalar uchun, keling, asosiy protseduraga ega oddiy kod moduli (ilova boshlanganda bajarila boshlaydi) va WorkerThreadClass sinfining modulidan iborat Console tipidagi yangi VB ilovasini yaratamiz:

Yaratilgan dasturni ishga tushiramiz. Konsol oynasi paydo bo'ladi, unda siz ishlaydigan hisoblash jarayoni (WorkerThread) modelini ko'rsatadigan belgilarning aylantiruvchi qatorini ko'rasiz. Keyin qo'ng'iroq qilish jarayoni (Asosiy) tomonidan chiqarilgan xabar oynasi paydo bo'ladi va nihoyat biz rasmda ko'rsatilgan rasmni ko'ramiz. 2 (agar siz modellashtirilgan jarayonning bajarilish tezligidan qoniqmasangiz, WorkerThread protsedurasida "a" o'zgaruvchisi bilan ba'zi arifmetik amallarni olib tashlang yoki qo'shing).

Iltimos, diqqat qiling: "Birinchi mavzu boshlandi" xabar oynasi WorkerThread jarayoni boshlanganidan keyin sezilarli kechikish bilan paydo bo'ldi (oldingi xatboshida tasvirlangan shaklda bunday xabar ButtonStart tugmasini bosgandan so'ng deyarli darhol paydo bo'ladi) . Buning sababi, hodisa protseduralari shakl ustida ishlashda boshlangan jarayondan ustundir. Konsol ilovasida barcha protseduralar bir xil ustuvorlikka ega. Biz ustuvorliklar masalasini keyinroq muhokama qilamiz, ammo hozircha chaqiruv chizig'ini (Asosiy) eng yuqori ustuvorlikka o'rnatamiz:

Thread.CurrentThread.Priority = _ ThreadPriority.Highest Thread1.Start ()

Endi oyna deyarli darhol paydo bo'ladi. Ko'rib turganingizdek, Thread ob'ektining nusxalarini yaratishning ikki yo'li mavjud. Birinchidan, biz ulardan birinchisini qo'lladik - biz yangi ob'ekt (ip) Thread1 yaratdik va u bilan ishladik. Ikkinchi variant esa statik CurrentThread usulidan foydalanib, hozirda ishlayotgan ip uchun Thread obyektini olishdir. Main protsedurasi o'zi uchun yuqoriroq ustuvorlikni shunday belgilab beradi, lekin u buni boshqa har qanday ish zarrachasi uchun bajarishi mumkin, masalan:

Thread1.Priority = ThreadPriority.Lowest Thread1.Start ()

Ishlayotgan jarayonni boshqarish imkoniyatlarini ko'rsatish uchun asosiy protsedura oxiriga quyidagi kod qatorlarini qo'shing:

Endi bir vaqtning o'zida sichqonchaning ba'zi operatsiyalarini bajarayotganda dasturni ishga tushiring (umid qilamanki, siz WorkerThread-da kerakli kechikish darajasini tanladingiz, shunda jarayon juda tez emas, balki juda sekin ham emas).

Birinchidan, konsol oynasida "1-jarayon" boshlanadi va "Birinchi mavzu boshlandi" xabari paydo bo'ladi. "1-jarayon" ishlamoqda va siz tezda xabar oynasidagi OK tugmasini bosasiz.

Keyinchalik - "1-jarayon" davom etadi, lekin ikki soniyadan so'ng "Mavzu to'xtatildi" xabari paydo bo'ladi. 1-jarayon qotib qoldi. Xabar oynasida OK tugmasini bosing: 1-jarayon davom etdi va muvaffaqiyatli yakunlandi.

Ushbu parchada biz joriy jarayonni to'xtatib turish uchun Kutish usulidan foydalandik. Eslatma: Kutish statik usul bo'lib, faqat joriy jarayonga qo'llanilishi mumkin, Thread ning har qanday misolida emas. Til sintaksisi Thread1.Sleep yoki Thread.Sleep yozish imkonini beradi, lekin bu holda CurrentThread obyekti hali ham ishlatiladi.

Kutish usuli 0 argumentidan ham foydalanishi mumkin.Bunday holda joriy oqim oʻziga ajratilgan vaqt qismining foydalanilmagan qolgan qismini chiqaradi.

Kutish uchun yana bir qiziqarli foydalanish holati Timeout.Infinite qiymatiga ega. Bunday holda, holat Thread.Interrupt usuli yordamida boshqa ip bilan uzilgunga qadar, ip cheksiz muddatga to'xtatiladi.

Tashqi ipni boshqa ipdan ikkinchisini to'xtatmasdan to'xtatib turish uchun siz Thread.Suspend usuliga qo'ng'iroq qilishingiz kerak. Shunda yuqoridagi kodda qilganmiz Thread.Resume usuli bilan uning bajarilishini davom ettirish mumkin bo'ladi.

Ip sinxronizatsiyasi haqida bir oz

Ko'p oqimli ilovalarni yozishda mavzularni sinxronlash asosiy tashvishlardan biridir va System.Threading maydoni buni amalga oshirish uchun keng ko'lamli vositalarni taqdim etadi. Lekin endi biz faqat Thread.Join usuli bilan tanishamiz, bu sizga ipning bajarilishini yakunlashini kuzatish imkonini beradi. Bu qanday ishlashini ko'rish uchun Mainning oxirgi qatorlarini ushbu kod bilan almashtiring:

Jarayon ustuvorligini boshqarish

Tarmoqlar orasidagi protsessor vaqt bo'laklarini taqsimlash Thread.Priority xossasi shaklida o'rnatiladigan ustuvorliklar yordamida amalga oshiriladi. Ishlash vaqtida yaratilgan oqimlar beshta qiymatga o'rnatilishi mumkin: Eng yuqori, AboveNormal, Oddiy (standart), BelowNormal va Lowest. Prioritetlar iplarning bajarilish tezligiga qanday ta'sir qilishini ko'rish uchun asosiy protsedura uchun quyidagi kodni yozamiz:

Sub Main () "birinchi jarayonning tavsifi Dim Thread1 As Thread Dim oWorker1 As New WorkerThreadClass () Thread1 = New Thread (AddressOf _ oWorker1.WorkerThread)" Thread1.Priority = _ "ThreadPriority:1W boshlang'ich ma'lumotlar uzatish." Start = 1 oWorker1.Finish = 10 oWorker1.ThreadName = "Orga sanash 1" oWorker1.SymThread = "." "ikkinchi jarayonning tavsifi Dim Thread2 As Thread Dim oWorker2 As New WorkerThreadClass () Thread2 = New Thread (AddressOf _ oWorker2.WorkerThread)" dastlabki ma'lumotlarni o'tkazing: oWorker2.Start = 11 oWorker2.Start = 11 oWorker2.0Thread oWorker2 =Counter2. 2" oWorker .SymThread = "*" "" poyga boshlanmoqda Thread.CurrentThread.Priority = _ ThreadPriority.Highest Thread1.Start () Thread2.Start () "Joriylar tugashi kutilmoqda Thread1.Join.Jo (22) ) MsgBox ("Har ikki jarayon tugadi") End Sub

E'tibor bering, bu bir nechta mavzularni yaratish uchun bitta sinfdan foydalanadi. Keling, dasturni ishga tushiramiz va ikkita ipning bajarilishi dinamikasini ko'rib chiqamiz (3-rasm). Bu erda siz umuman olganda, ular bir xil tezlikda bajarilganligini ko'rishingiz mumkin, birinchisi oldingi ishga tushirilganligi sababli biroz oldinda.

Endi, birinchi ipni boshlashdan oldin, uning ustuvorligini bir daraja pastroq qilib qo'ying:

Thread1.Priority = _ ThreadPriority.BelowNormal

Rasm keskin o'zgardi: ikkinchi oqim deyarli hamma vaqtni birinchisidan uzoqlashtirdi (4-rasm).

Qo'shilish usulidan foydalanishga ham e'tibor bering. Uning yordami bilan biz iplarni sinxronlashtirishning juda keng tarqalgan variantini amalga oshiramiz, unda asosiy dastur bir nechta parallel hisoblash jarayonlarining tugashini kutadi.

Xulosa

Biz hozirgina koʻp tarmoqli .NET ilovalarini ishlab chiqish asoslariga toʻxtalib oʻtdik. Eng qiyin va amalda dolzarb masalalardan biri bu iplarni sinxronlashtirishdir. Ushbu maqolada tasvirlangan Thread ob'ektidan foydalanishga qo'shimcha ravishda (u biz bu erda ko'rib chiqmagan ko'plab usullar va xususiyatlarga ega), Monitor va Mutex sinflari, shuningdek, lock (C #) va SyncLock (VB.NET) iboralari, ipni boshqarishda juda muhim rol o'ynaydi. ...

Ushbu texnologiyaning batafsil tavsifi kitoblarning alohida boblarida berilgan va men ".NETda ko'p o'rinli ishlash" mavzusida juda qisqa xulosa sifatida bir nechta iqtiboslarni keltirmoqchiman (men to'liq roziman).

"Agar siz yangi boshlovchi bo'lsangiz, iplarni yaratish va jo'natish uchun qo'shimcha xarajatlar bitta oqimli dasturni tezroq ishga tushirishi mumkinligini bilib hayron bo'lishingiz mumkin ... Shuning uchun har doim ham bitta va ko'p tarmoqli prototiplarni sinab ko'ring."

"Siz ko'p qirrali dizayningizdan ehtiyot bo'lishingiz va umumiy ob'ektlar va o'zgaruvchilarga kirishni qattiq nazorat qilishingiz kerak."

"Ko'p ish zarralarini standart yondashuv sifatida ko'rmang."

"Men tajribali VB dasturchilaridan iborat auditoriyadan VB ning kelajakdagi versiyasida bepul rezyumega ega bo'ladimi, deb so'radim. Deyarli hamma qo'llarini ko'tardi. Keyin u nima qilayotganini kim biladi, deb so'radim. Bu safar faqat bir nechta odam qo'llarini ko'tardi. va ularning yuzlarida tabassum bor edi."

"Agar siz ko'p bosqichli ilovalarni loyihalashdagi qiyinchiliklardan qo'rqmasangiz, to'g'ri qo'llanilganda, ko'p ish zarralari dastur ish faoliyatini sezilarli darajada yaxshilaydi."

O'zimcha shuni qo'shimcha qilamanki, ko'p tarmoqli .NET ilovalarini yaratish texnologiyasi (ko'plab boshqa .NET texnologiyalari kabi) umuman olganda ishlatiladigan tildan deyarli mustaqildir. Shuning uchun men ishlab chiquvchilarga ma'lum bir texnologiyani namoyish qilish uchun qaysi dasturlash tilini tanlashlaridan qat'i nazar, turli kitoblar va maqolalarni o'rganishni maslahat beraman.

Adabiyot:

  1. Den Appleman. VB.NET ga o'tish: strategiyalar, tushunchalar, kod / Per. ingliz tilidan - SPb .: "Piter", 2002, - 464 b.: kasal.
  2. Tom Archer. C # asoslari. Eng yangi texnologiyalar / Per. ingliz tilidan - M .: "Rus nashriyoti" nashriyoti va savdo uyi, 2001. - 448 b.: kasal.

Ko'p vazifali va ko'p ish zarralari

Keling, ushbu oddiy bayonotdan boshlaylik: 32-bitli Windows operatsion tizimlari ma'lumotlarni qayta ishlashning ko'p vazifali (ko'p ishlov berish) va ko'p oqimli rejimlarini qo'llab-quvvatlaydi. Ular buni qanchalik yaxshi bajarishlarini muhokama qilish mumkin, ammo bu boshqa savol.

Ko'p vazifali ishlash - bu kompyuter bir vaqtning o'zida bir nechta vazifalarni parallel ravishda bajarishi mumkin bo'lgan ish tartibi. Agar kompyuterda bitta protsessor bo'lsa, OS ba'zi qoidalarga ko'ra turli xil vazifalarni tezda almashtirishi mumkin bo'lgan psevdoparallelizm haqida gapirayapmiz. Vazifa - bu qandaydir mantiqiy amallarni bajaradigan dastur yoki dasturning (ilovaning) bir qismi va OT resurslarni ajratadigan birlikdir. Biroz soddalashtirilgan shaklda, Windows-da vazifa alohida bajariladigan modul (EXE, DLL) sifatida amalga oshiriladigan har bir dasturiy komponent deb taxmin qilishimiz mumkin. Windows uchun "vazifa" tushunchasi "jarayon" bilan bir xil ma'noga ega, bu, xususan, dastur kodining qat'iy ravishda unga ajratilgan manzil maydonida bajarilishini anglatadi.

Multitaskingning ikkita asosiy turi mavjud - kooperativ va preemptiv. Windows-ning oldingi versiyalarida amalga oshirilgan birinchi variant, faqat faol vazifa OTga kirgan paytdagi vazifalar o'rtasida almashishni ta'minlaydi (masalan, kiritish / chiqish uchun). Bunday holda, har bir ip boshqaruvni OTga qaytarish uchun javobgardir. Agar vazifa bunday operatsiyani bajarishni unutgan bo'lsa (masalan, u halqaga yopishib qolgan bo'lsa), bu ko'pincha butun kompyuterning muzlashiga olib keldi.

Preemptive multitasking - bu OTning o'zi har bir mavzuga o'z vaqtini berish uchun javobgar bo'lgan rejim bo'lib, shundan so'ng u (boshqa vazifalardan so'rovlar bo'lsa) avtomatik ravishda ushbu mavzuni to'xtatadi va keyin nima boshlashni hal qiladi. Ilgari bu rejim "vaqtni almashish" deb nomlangan.

Oqim nima? Tarmoq - bu avtonom hisoblash jarayoni, lekin OT darajasida emas, balki vazifa doirasida. Tarmoq va "jarayon-topshiriq" o'rtasidagi tub farq shundaki, topshiriqning barcha iplari bitta manzil maydonida bajariladi, ya'ni ular umumiy xotira resurslari bilan ishlashlari mumkin. Aynan shu erda ularning afzalliklari (ma'lumotlarni parallel qayta ishlash) va kamchiliklari (dasturning ishonchliligiga tahdid) yotadi. Bu erda shuni yodda tutish kerakki, ko'p vazifali bo'lsa, OT birinchi navbatda ilovalarni himoya qilish uchun javobgardir va ko'p ish zarralaridan foydalanganda ishlab chiqaruvchining o'zi.

E'tibor bering, bitta protsessorli tizimlarda ko'p vazifali rejimdan foydalanish ko'p vazifali tizimning umumiy unumdorligini oshirishga imkon beradi (garchi har doim ham bo'lmasa-da, chunki kalitlar soni ko'payishi bilan OT egallagan resurslar ulushi ortadi). Ammo ma'lum bir vazifani bajarish vaqti har doim, hatto ozgina bo'lsa ham, operatsion tizimning qo'shimcha ishi tufayli ortadi.

Agar protsessor vazifalar bilan og'ir yuklangan bo'lsa (masalan, kiritish-chiqarish uchun minimal uzilishlar bilan, masalan, sof matematik muammolarni hal qilishda), haqiqiy umumiy samaradorlikni oshirishga faqat ko'p protsessorli tizimlardan foydalanganda erishiladi. Bunday tizimlar parallellashtirishning turli modellariga imkon beradi - vazifa darajasida (har bir vazifa faqat bitta protsessorni egallashi mumkin, iplar esa faqat psevdoparallelizmda bajariladi) yoki ip darajasida (bir vazifa o'z iplari bilan bir nechta protsessorni egallashi mumkin).

Bu erda, shuningdek, 60-yillarning oxirida ota-bobosi IBM System / 360 oilasi bo'lgan kuchli umumiy hisoblash tizimlaridan foydalanishda eng dolzarb vazifalardan biri optimal ko'p vazifali boshqaruv variantini tanlash edi, shu jumladan dinamik rejimda, turli parametrlarni hisobga olgan holda. Asosan, ko'p vazifali boshqaruv operatsion tizimning funktsiyasidir. Ammo u yoki bu variantni amalga oshirish samaradorligi to'g'ridan-to'g'ri butun kompyuterning va ayniqsa protsessorning arxitekturasining o'ziga xos xususiyatlariga bog'liq. Misol uchun, xuddi shu yuqori samarali IBM System / 360 biznes vazifalari uchun umumiy tizimlarda yaxshi ishlagan, ammo ayni paytda u "real vaqt" sinfidagi muammolarni hal qilish uchun mutlaqo yaroqsiz edi. O'sha paytda DEC PDP 11/20 kabi sezilarli darajada arzonroq va sodda mini-kompyuterlar bu sohada etakchi bo'lgan.

Yangi boshlanuvchilar uchun qaysi mavzu ko'proq savol va qiyinchiliklar tug'diradi? Men o'qituvchim va Java dasturchisi Aleksandr Pryaxindan bu haqda so'raganimda, u darhol javob berdi: "Multithreading". Ushbu maqolani tayyorlashda g'oya va yordam uchun unga rahmat!

Biz ilovaning ichki dunyosi va uning jarayonlarini ko'rib chiqamiz, ko'p oqimning mohiyati nima ekanligini, u qachon foydali ekanligini va uni qanday amalga oshirishni aniqlaymiz - misol sifatida Java. Agar siz boshqa OOP tilini o'rganayotgan bo'lsangiz, tashvishlanmang: asosiy tamoyillar bir xil.

Oqimlar va ularning kelib chiqishi haqida

Ko'p ish zarralarini tushunish uchun avvalo jarayon nima ekanligini tushunib olaylik. Jarayon - bu OS dasturni ishga tushirish uchun ajratadigan virtual xotira va resurslarning bir qismi. Agar siz bir xil dasturning bir nechta nusxasini ochsangiz, tizim har biri uchun jarayonni ajratadi. Zamonaviy brauzerlarda har bir yorliq uchun alohida jarayon javobgar bo'lishi mumkin.

Ehtimol, siz Windows-ning "Vazifa menejeri" (Linux-da bu "Tizim monitori") bilan duch kelgansiz va bilasizki, keraksiz ishlaydigan jarayonlar tizimni yuklaydi va ularning eng "og'ir"lari tez-tez muzlab qoladi, shuning uchun ularni majburan tugatish kerak. .

Lekin foydalanuvchilar ko‘p vazifani yaxshi ko‘radilar: ularga non bermang – shunchaki o‘nlab derazalarni oching va oldinga va orqaga sakrab chiqing. Dilemma mavjud: ilovalarning bir vaqtning o'zida ishlashini ta'minlash va shu bilan birga tizimdagi yukni sekinlashtirmaslik uchun kamaytirish kerak. Aytaylik, apparat egalarining ehtiyojlarini qondira olmaydi - muammoni dasturiy ta'minot darajasida hal qilishingiz kerak.

Biz protsessor ko'proq ko'rsatmalarni bajarishini va vaqt birligi uchun ko'proq ma'lumotlarni qayta ishlashni xohlaymiz. Ya'ni, biz har bir vaqt bo'limiga bajarilgan kodni ko'proq sig'dirishimiz kerak. Kodni bajarish birligini ob'ekt sifatida tasavvur qiling - bu ip.

Murakkab ishni bir nechta oddiylarga ajratsangiz, unga yaqinlashish osonroq bo'ladi. Shunday qilib, xotira bilan ishlashda: "og'ir" jarayon kamroq resurslarni egallagan va kodni kalkulyatorga etkazish ehtimoli yuqori bo'lgan iplarga bo'linadi (qanday qilib aniq - quyida ko'ring).

Har bir dastur kamida bitta jarayonga ega va har bir jarayonda kamida bitta oqim mavjud bo'lib, ular asosiy oqim deb ataladi va kerak bo'lganda yangilari ishga tushiriladi.

Iplar va jarayonlar o'rtasidagi farq

    Mavzular jarayon uchun ajratilgan xotiradan foydalanadi va jarayonlar o'zlarining xotira maydonini talab qiladi. Shuning uchun iplar tezroq yaratiladi va tugallanadi: tizim har safar ularga yangi manzil maydonini ajratishi va keyin uni qo'yib yuborishi shart emas.

    Har bir ishni o'z ma'lumotlari bilan qayta ishlaydi - ular faqat jarayonlararo aloqa mexanizmi orqali biror narsa almashishlari mumkin. Mavzular bir-birining ma'lumotlari va resurslariga bevosita kirishadi: o'zgartirilgan narsa darhol hamma uchun mavjud. Ip jarayondagi "do'st" ni boshqarishi mumkin, jarayon esa faqat uning "qizlari" ni boshqaradi. Shuning uchun oqimlar o'rtasida almashish tezroq va ular orasidagi aloqa osonroq.

Bundan qanday xulosa chiqarish mumkin? Agar siz katta hajmdagi ma'lumotlarni iloji boricha tezroq qayta ishlashingiz kerak bo'lsa, uni alohida iplar bilan qayta ishlanishi mumkin bo'lgan qismlarga bo'ling va keyin natijani birlashtiring. Bu resurslarga muhtoj bo'lgan jarayonlarni ishlab chiqarishdan ko'ra yaxshiroqdir.

Lekin nima uchun Firefox kabi mashhur dastur bir nechta jarayonlarni yaratish yo'lidan boradi? Aynan brauzer uchun ajratilgan yorliqlar ishonchli va moslashuvchan bo'lganligi sababli. Agar bitta jarayonda biror narsa noto'g'ri bo'lsa, butun dasturni tugatish shart emas - ma'lumotlarning kamida bir qismini saqlash mumkin.

Ko'p ish zarralari nima

Shunday qilib, biz asosiy narsaga keldik. Ko'p ish zarralari - bu dastur jarayoni protsessor tomonidan parallel ravishda - vaqtning bir birligida qayta ishlanadigan iplarga bo'linishi.

Hisoblash yuki ikki yoki undan ortiq yadrolar orasida taqsimlanadi, shuning uchun interfeys va boshqa dastur komponentlari bir-birining ishini sekinlashtirmaydi.

Ko'p tarmoqli ilovalar bir yadroli protsessorlarda ishga tushirilishi mumkin, ammo keyin iplar navbat bilan bajariladi: birinchisi ishladi, uning holati saqlanib qoldi - ikkinchisiga ishlashga ruxsat berildi, saqlangan - birinchisiga qaytarildi yoki uchinchisini ishga tushirdi, va boshqalar.

Ish bilan band odamlar faqat ikkita qo'li borligidan shikoyat qiladilar. Jarayonlar va dasturlar vazifani imkon qadar tezroq bajarish uchun kerak bo'lganda ko'p qo'llarga ega bo'lishi mumkin.

Signalni kuting: ko'p tarmoqli ilovalarda sinxronlash

Tasavvur qiling-a, bir vaqtning o'zida bir nechta mavzular bir xil ma'lumotlar maydonini o'zgartirishga harakat qilmoqda. Oxir-oqibat kimning o'zgarishlari qabul qilinadi va kimning o'zgarishlari bekor qilinadi? Umumiy manbalar bilan chalkashmaslik uchun iplar o'z harakatlarini muvofiqlashtirishi kerak. Buning uchun ular signallar yordamida ma'lumot almashadilar. Har bir mavzu boshqalarga nima qilayotganini va qanday o'zgarishlarni kutish kerakligini aytadi. Shunday qilib, resurslarning joriy holati haqidagi barcha mavzular ma'lumotlari sinxronlashtiriladi.

Sinxronizatsiyaning asosiy vositalari

O'zaro istisno (o'zaro istisno, mutex deb qisqartirilgan) - hozirda umumiy resurslar bilan ishlashga ruxsat berilgan mavzuga o'tadigan "bayroq". Ishg'ol qilingan xotira maydoniga boshqa oqimlarning kirishini yo'q qiladi. Ilovada bir nechta mutekslar bo'lishi mumkin va ular jarayonlar o'rtasida taqsimlanishi mumkin. Bir jihat bor: mutex ilovani har safar operatsion tizim yadrosiga kirishga majbur qiladi, bu esa qimmatga tushadi.

Semafor - ma'lum bir vaqtda resursga kirishi mumkin bo'lgan mavzular sonini cheklash imkonini beradi. Bu protsessorga to'siqlar mavjud bo'lgan kodni bajarishda yukni kamaytiradi. Muammo shundaki, iplarning optimal soni foydalanuvchi mashinasiga bog'liq.

Tadbir - sodir bo'lganda boshqaruv kerakli ipga o'tkaziladigan shartni aniqlaysiz. Streamlar bir-birining harakatlarini ishlab chiqish va mantiqiy davom ettirish uchun voqea ma'lumotlarini almashadi. Biri ma'lumotni oldi, ikkinchisi uning to'g'riligini tekshirdi, uchinchisi uni qattiq diskda saqladi. Voqealar bekor qilinishi bilan farqlanadi. Agar biror voqea haqida bir nechta mavzularni xabardor qilishingiz kerak bo'lsa, signalni to'xtatish uchun bekor qilish funksiyasini qo'lda o'rnatishingiz kerak bo'ladi. Agar faqat bitta maqsadli mavzu bo'lsa, siz avtomatik tiklash hodisasini yaratishingiz mumkin. Oqimga yetib borgach, u signalni o'zi to'xtatadi. Moslashuvchan oqim nazorati uchun hodisalar navbatga qo'yilishi mumkin.

Tanqidiy qism - loop hisoblagich va semaforni birlashtirgan yanada murakkab mexanizm. Hisoblagich semaning boshlanishini kerakli vaqtga kechiktirishga imkon beradi. Afzalligi shundaki, yadro faqat bo'lim band bo'lsa va semaforni yoqish kerak bo'lsa faollashadi. Qolgan vaqtda ip foydalanuvchi rejimida ishlaydi. Afsuski, bo'lim faqat bitta jarayonda ishlatilishi mumkin.

Java-da multithreading qanday amalga oshiriladi

Thread klassi Java-da iplar bilan ishlash uchun javobgardir. Vazifani bajarish uchun yangi ip yaratish Thread sinfining namunasini yaratish va uni kerakli kod bilan bog'lashni anglatadi. Bu ikki usulda amalga oshirilishi mumkin:

    subclass Thread;

    sinfingizda Runnable interfeysini amalga oshiring va keyin sinf misollarini Thread konstruktoriga o'tkazing.

Garchi biz boshi berk ko'chaga kirmagan bo'lsak-da, iplar bir-birining ishini to'sib qo'yganda va qotib qolganda, biz buni keyingi maqolaga qoldiramiz.

Java multithreading misoli: muteksli stol tennisi

Agar biror dahshatli narsa sodir bo'ladi deb o'ylasangiz, nafas oling. Sinxronizatsiya ob'ektlari bilan ishlashni deyarli o'ynoqi usulda ko'rib chiqamiz: ikkita ip mutex tomonidan tashlanadi.Ammo aslida siz bir vaqtning o'zida faqat bitta ip umumiy foydalanish mumkin bo'lgan ma'lumotlarni qayta ishlay oladigan haqiqiy dasturni ko'rasiz.

Birinchidan, biz allaqachon bilgan Thread xususiyatlarini meros qilib oladigan sinf yaratamiz va kickBall usulini yozamiz:

Ommaviy sinf PingPongThread mavzuni kengaytiradi (PingPongThread (String nomi) (this.setName (nom); // mavzu nomini bekor qilish) @Override umumiy bekor yugurish () (Ball ball = Ball.getBall (); while (ball.isInGame () ) (kickBall (to'p);)) xususiy bekor kickBall (Ball ball) (agar (! ball.getSide (). teng bo'lsa (getName ())) (ball.kick (getName ());)))

Endi to'pga g'amxo'rlik qilaylik. U biz bilan oddiy emas, balki esda qolarli bo'ladi: kim uni, qaysi tomondan va necha marta urganini ayta oladi. Buning uchun biz mutexdan foydalanamiz: u har bir ipning ishi haqida ma'lumot to'playdi - bu izolyatsiya qilingan iplarning bir-biri bilan aloqa qilishiga imkon beradi. 15-zarbadan so'ng to'pni jiddiy shikastlamaslik uchun o'yindan chiqaramiz.

Ommaviy toifadagi to‘p (maxsus int zarbalari = 0; shaxsiy statik to‘p nusxasi = yangi to‘p (); xususiy String tomoni = ""; shaxsiy to‘p () () statik to‘p getBall () (qaytish namunasi;) sinxronlangan bekor zarbasi (String o‘yinchisi nomi) (tepkilar ++; yon = o'yinchi nomi; System.out.println (tepkilar + "" + yon);) String getSide () (qaytish tomoni;) mantiqiy isInGame () (qaytish (tepish)< 15); } }

Va endi ikkita o'yinchi ipi sahnaga kirmoqda. Keling, ularni ortiqcha uzatmasdan Ping va Pong deb ataylik:

Ommaviy sinf PingPongGame (PingPongThread player1 = yangi PingPongThread ("Ping"); PingPongThread player2 = yangi PingPongThread ("Pong"); To'p to'pi; PingPongGame () (to'p = Ball.getBall ();) bekor startGame (Istisno 1 o'yinni tashlaydi) .start (); player2.start ();))

"Odamlar bilan to'lgan stadion - o'yinni boshlash vaqti keldi." Uchrashuvning ochilishini rasman e'lon qilamiz - arizaning asosiy sinfida:

Ommaviy PingPong klassi (ommaviy statik bekor asosiy (String args) InterruptedException o'yinini chiqaradi (PingPongGame o'yini = yangi PingPongGame (); game.startGame ();))

Ko'rib turganingizdek, bu erda g'azablangan narsa yo'q. Bu hozircha ko'p qirrali ishlashga kirish, lekin siz u qanday ishlashini allaqachon bilasiz va siz tajriba qilishingiz mumkin - o'yin davomiyligini zarbalar soni bilan emas, balki vaqt bilan cheklang. Ko‘p ish zarralari mavzusiga keyinroq qaytamiz – java.util.concurrent paketini, Akka kutubxonasini va o‘zgaruvchan mexanizmni ko‘rib chiqamiz. Keling, Pythonda multithreadingni amalga oshirish haqida ham gapiraylik.

Sizga maqola yoqdimi? Do'stlar bilan baham ko'rish uchun: