Пример вишеструког навоја у Питхону са глобалним закључавањем тумача (ГИЛ)

Програмски језик Питхон вам омогућава да користите вишепроцесну или вишеслојну обраду текста. У овом водичу ћете научити како писати вишеслојне апликације у Питхону.

Шта је нит?

Нит је јединица за изузимање при истовременом програмирању. Мултитхреадинг је техника која омогућава ЦПУ -у да извршава многе задатке једног процеса истовремено. Ове нити се могу извршавати појединачно док деле своје ресурсе процеса.

Шта је процес?

Процес је у основи програм у извођењу. Када покренете апликацију на рачунару (попут прегледача или уређивача текста), оперативни систем ствара датотеку процес.

Шта је вишенаменско решавање у Питхону?

Вишеструко нитање у Питхону програмирање је добро позната техника у којој више нити у процесу дели свој простор података са главном нити што чини дељење информација и комуникацију унутар нити једноставним и ефикасним. Нити су лакше од процеса. Више нити се могу извршавати појединачно док дијеле своје процесне ресурсе. Сврха вишеслојности је покретање више задатака и функционалних ћелија истовремено.

Шта је вишепроцесирање?

Вишепроцесирање вам омогућава да истовремено покренете више неповезаних процеса. Ови процеси не деле своје ресурсе и комуницирају путем ИПЦ -а.

Питхон Вишенитно вс Вишпроцесорско

Да бисте разумели процесе и нити, размотрите овај сценарио: Датотека .еке на вашем рачунару је програм. Када га отворите, ОС га учитава у меморију, а ЦПУ га извршава. Инстанца програма који је сада покренут назива се процес.

Сваки процес ће имати 2 основне компоненте:

  • Код
  • Подаци

Сада процес може садржати један или више подделова тзв нити. Ово зависи од архитектуре ОС -а.. Можете размишљати о нити као о делу процеса који оперативни систем може засебно извршити.

Другим речима, то је низ инструкција које ОС може самостално покренути. Нити унутар једног процеса деле податке тог процеса и осмишљене су да раде заједно ради олакшавања паралелизма.

У овом водичу ћете научити,

Зашто користити Мултитхреадинг?

Мултитхреадинг вам омогућава да поделите апликацију на више подзадатака и покренете те задатке истовремено. Ако правилно користите вишеструко нитање, брзина апликације, перформансе и исцртавање могу се побољшати.

Питхон МултиТхреадинг

Питхон подржава конструкције како за вишепроцесну тако и за вишеструку нит. У овом водичу ћете се првенствено фокусирати на имплементацију вишеслојни апликације са питхон -ом. Постоје два главна модула која се могу користити за руковање нитима у Питхону:

  1. Тхе конац модул, и
  2. Тхе тхреадинг модул

Међутим, у питхону постоји и нешто што се назива глобално закључавање тумача (ГИЛ). Не дозвољава много повећање перформанси, па чак и може смањити перформансе неких вишенавојних апликација. Научићете све о томе у предстојећим одељцима овог водича.

Модули Тхреад и Тхреадинг

Два модула о којима ћете научити у овом водичу су модул навоја и модул за навоје .

Међутим, нитни модул је већ дуго застарео. Почевши од Питхон 3, означен је као застарео и доступан му је само као __тхреад ради компатибилности са претходним верзијама.

Требало би да користите виши ниво тхреадинг модул за апликације које намеравате да примените. Модул нити је овде покривен само у образовне сврхе.

Модул нити

Синтакса за креирање нове нити помоћу овог модула је следећа: | _+_ |

У реду, сада сте покрили основну теорију за почетак кодирања. Дакле, отворите свој ИДЛЕ или бележницу и откуцајте следеће: | _+_ |

Сачувајте датотеку и притисните Ф5 да бисте покренули програм. Ако је све урађено исправно, ово би требало да видите:

У предстојећим одељцима ћете сазнати више о условима трке и начину на који се с њима поступа

ОБЈАШЊЕЊЕ КОДА

  1. Ови изрази увозе модул времена и нити који се користе за руковање извршавањем и одлагањем Питхон нити.
  2. Овде сте дефинисали функцију која се зове тхреад_тест, који ће бити позван од стране старт_нев_тхреад метода. Функција покреће вхиле петљу за четири итерације и штампа име нити која ју је позвала. Када се итерација заврши, штампа се порука која каже да је нит завршила са извршавањем.
  3. Ово је главни одељак вашег програма. Овде једноставно зовете старт_нев_тхреад метод са тхреад_тест функционише као аргумент.

    Ово ће створити нову нит за функцију коју проследите као аргумент и почети да је извршавате. Имајте на уму да ово можете заменити (нит _ тест) са било којом другом функцијом коју желите да покренете као нит.

Модул Тхреадинг

Овај модул је имплементација тхреадинга на високом нивоу у питхону и де фацто стандард за управљање вишедимензионалним апликацијама. Пружа широк спектар функција у поређењу са навојним модулом.

Структура модула Тхреадинг



Ево листе неких корисних функција дефинисаних у овом модулу:

Назив функције Опис
ацтивеЦоунт () Приказује број од Тхреад предмете који су још живи
цуррентТхреад () Враћа тренутни објекат класе Тхреад.
набројати () Наводи све активне Тхреад објекте.
исДаемон () Враћа труе ако је нит демон.
је жив() Враћа труе ако је нит још увек жива.
Методе класе нити
почетак() Покреће активност нити. Мора се позвати само једном за сваку нит јер ће изазвати грешку у току извођења ако се позове више пута.
трцати() Ова метода означава активност нити и може је заменити класа која проширује класу Нит.
придружити() Он блокира извршавање другог кода све док се нит на којој је позвана метода јоин () не прекине.

Позадина: Класа нити

Пре него што започнете кодирање вишежитних програма помоћу нитног модула, важно је разумети класу Тхреад. Класа тхреад је примарна класа која дефинише шаблон и операције нити у питхону.

Најчешћи начин за креирање вишенавојне питхон апликације је декларисање класе која проширује Тхреад класу и замењује њен рун () метод.

Укратко, класа Тхреад означава секвенцу кода која се изводи у засебној верзији конац контроле.

Дакле, приликом писања вишеслојне апликације, урадићете следеће:

  1. дефинишите класу која проширује класу Тхреад
  2. Замени __у томе__ градитељ
  3. Замени трцати() метода

Након што је направљен објект нити, почетак() Метода се може користити за почетак извршавања ове активности и придружити() метода се може користити за блокирање свих осталих кодова док се тренутна активност не заврши.

Сада, покушајмо да употребимо нитни модул за имплементацију вашег претходног примера. Поново покрените ИДЛЕ и упишите следеће: | _+_ |

Ово ће бити излаз када извршите горњи код:

ОБЈАШЊЕЊЕ КОДА

  1. Овај део је исти као и наш претходни пример. Овде увозите модул времена и нити који се користи за руковање извршавањем и кашњењима Питхон нити.
  2. У овом делу креирате класу која се зове тхреадтестер, која наслеђује или проширује Тхреад класе модула навоја. Ово је један од најчешћих начина стварања нити у питхону. Међутим, требали бисте само надјачати конструктор и трцати() метод у вашој апликацији. Као што можете видети у горњем узорку кода, __у томе__ метода (конструктор) је надјачана.

    Слично, такође сте поништили трцати() метода. Садржи код који желите да извршите унутар нити. У овом примеру позвали сте функцију тхреад_тест ().

  3. Ово је метода тхреад_тест () која узима вредност и као аргумент, смањује га за 1 при свакој итерацији и петља кроз остатак кода све док и не постане 0. У свакој итерацији штампа име тренутно извршаване нити и спава секунде чекања (што се такође узима као аргумент).
  4. тхреад1 = тхреадтестер (1, 'Прва нит', 1)

    Овде стварамо нит и преносимо три параметра која смо декларисали у __инит__. Први параметар је ид нити, други параметар је назив нити, а трећи параметар је бројач, који одређује колико пута би требало да се изврши петља вхиле.

  5. тхреад2.старт ()

    Метода покретања се користи за покретање извршавања нити. Интерно, функција старт () позива методу рун () ваше класе.

  6. тхреад3.јоин ()

    Метод јоин () блокира извршавање другог кода и чека док се нит у којој је позван не заврши.

Као што већ знате, нити које се налазе у истом процесу имају приступ меморији и подацима тог процеса. Као резултат тога, ако више нити истовремено покушава да промени или приступи подацима истовремено, грешке се могу увући.

У следећем одељку видећете различите врсте компликација које се могу појавити када нити приступају подацима и критичном одељку без провере постојећих приступних трансакција.

Застоји и услови трке

Пре него што научите о застојима и условима трке, биће корисно да разумете неколико основних дефиниција везаних за паралелно програмирање:

  • Критички одељак

    То је фрагмент кода који приступа или мења дељене променљиве и мора се извршити као атомска трансакција.

  • Пребацивање контекста

    То је процес који ЦПУ прати да би сачувао стање нити пре преласка са једног задатка на други, тако да се касније може наставити са исте тачке.

Застоји

Застоји су најстрашнији проблем са којим се програмери суочавају при писању истовремених/вишеслојних апликација у питхону. Најбољи начин за разумевање застоја је коришћење проблема класичног примера информатике познатог као Проблем филозофа за ручавање.

Решење проблема филозофа за ручавање је следеће:

Пет филозофа седи на округлом столу са пет тањира шпагета (врста тестенина) и пет виљушки, како је приказано на дијаграму.

Проблем филозофа за ручавање

У било ком тренутку, филозоф мора или јести или размишљати.

Штавише, филозоф мора узети две виљушке поред себе (тј. Леву и десну виљушку) пре него што поједе шпагете. Проблем застоја настаје када свих пет филозофа истовремено подигну десну виљушку.

Пошто сваки од филозофа има једну виљушку, сви ће чекати да други спусте виљушку. Због тога нико од њих неће моћи да једе шпагете.

Слично, у истовременом систему, застој се јавља када различите нити или процеси (филозофи) покушају да истовремено добију дељене системске ресурсе (рачве). Као резултат тога, ниједан од процеса нема прилику да се изврши док чекају на други ресурс који држи неки други процес.

Тркачки услови

Услов трке је нежељено стање програма које се јавља када систем извршава две или више операција истовремено. На пример, размотрите ову једноставну фор петљу: | _+_ |

Ако стварате н број нити које покрећу овај код одједном, не можете одредити вредност и (коју нити деле) када програм заврши извршавање. То је зато што се у правом вишенавојном окружењу нити могу преклапати, а вредност и коју је нит дохватио и модификовао може се променити између када јој приступи нека друга нит.

Ово су две главне класе проблема који се могу јавити у вишеслојној или дистрибуираној питхон апликацији. У следећем одељку ћете научити како да превазиђете овај проблем синхронизовањем нити.

Синхронизација нити

За решавање услова трке, застоја и других проблема заснованих на нитима, модул за уређивање нити обезбеђује закључати објекат. Идеја је да када нит жели приступ одређеном ресурсу, добија закључавање за тај ресурс. Једном када нит закључа одређени ресурс, ниједна друга нит јој не може приступити док се брава не отпусти. Као резултат тога, промене у ресурсу ће бити атомске, а услови за трку ће бити избегнути.

Закључавање је примитив за синхронизацију на ниском нивоу који имплементира __тхреад модул. У било ком тренутку, брава може бити у једном од 2 стања: закључан или откључан. Подржава две методе:

  1. стећи()

    Када је стање закључавања откључано, позивањем методе аццепт () стање ће се променити у закључано и вратиће се. Међутим, ако је стање закључано, позив прикупити () је блокиран све док методу релеасе () не позове нека друга нит.

  2. издање()

    Метод релеасе () се користи за постављање стања на откључано, тј. За откључавање. Може се позвати било којом нити, не нужно оном која је стекла браву.

Ево примера коришћења закључавања у вашим апликацијама. Укључите ИДЛЕ и откуцајте следеће: | _+_ |

Сада, притисните Ф5. Требало би да видите излаз овако:

ОБЈАШЊЕЊЕ КОДА

  1. Овде једноставно креирате нову браву позивом на тхреадинг.Лоцк () фабричка функција. Интерно, Лоцк () враћа инстанцу најефикасније конкретне класе Лоцк коју одржава платформа.
  2. У првом изразу закључавање добијате позивањем методе прибављања (). Када је закључавање одобрено, штампате 'закључавање стечено' до конзоле. Када се заврши извршавање свих кодова за које желите да нит покрене, откључавате закључавање позивањем методе релеасе ().

Теорија је у реду, али како знате да је брава заиста радила? Ако погледате излаз, видећете да се свака изјава о штампању штампа тачно по један ред. Подсјетимо се да су у ранијем примјеру излази из исписа били случајни јер је више нити истовремено приступало методи принт (). Овде се функција штампања позива тек након што се закључа. Дакле, излази се приказују један по један и ред по ред.

Осим закључавања, питхон подржава и неке друге механизме за руковање синхронизацијом нити, као што је доле наведено:

  1. РЛоцкс
  2. Семафори
  3. Услови
  4. Догађаји, и
  5. Препреке

Глобално закључавање тумача (и како се носити с њим)

Пре него што пређемо у детаље питхон -овог ГИЛ -а, дефинишимо неколико термина који ће бити корисни за разумевање предстојећег одељка:

  1. Код везан за ЦПУ: ово се односи на било који део кода који ће ЦПУ директно извршити.
  2. И/О-везани код: ово може бити било који код који приступа систему датотека кроз ОС
  3. ЦПитхон: то је референца имплементација Питхона и може се описати као тумач написан на Ц и Питхон (програмски језик).

Шта је ГИЛ у Питхону?

Глобална брава тумача (ГИЛ) у питхону је закључавање процеса или мутекс који се користи при раду са процесима. Он осигурава да једна нит може приступити одређеном ресурсу у исто време и такође спречава употребу објеката и бајт кодова одједном. Ово користи једнонавојним програмима у повећању перформанси. ГИЛ у питхону је врло једноставан и лак за имплементацију.

Закључавање се може користити да би се осигурало да само једна нит има приступ одређеном ресурсу у датом тренутку.

Једна од карактеристика Питхона је да користи глобално закључавање сваког процеса тумача, што значи да сваки процес третира самог преводиоца питхона као ресурс.

На пример, претпоставимо да сте написали питхон програм који користи две нити за извођење и ЦПУ и 'И/О' операција. Када покренете овај програм, дешава се следеће:

  1. Питхон тумач ствара нови процес и покреће нити
  2. Када нит-1 почне да ради, прво ће стећи ГИЛ и закључати је.
  3. Ако тхреад-2 жели да се изврши сада, мораће да сачека ослобађање ГИЛ-а чак и ако је други процесор слободан.
  4. Претпоставимо сада да нит-1 чека на И/О операцију. У овом тренутку ће објавити ГИЛ, а нит-2 ће га набавити.
  5. Након завршетка И/О операција, ако нит-1 жели да се изврши сада, поново ће морати да сачека да ГИЛ ослободи нит-2.

Због тога само једна нит може приступити тумачу у било ком тренутку, што значи да ће постојати само једна нит која извршава питхон код у датом тренутку.

Ово је у реду са једнојезгреним процесором јер би за обраду нити користило скраћивање времена (погледајте први одељак овог водича). Међутим, у случају вишејезгрених процесора, функција везана за ЦПУ која се извршава на више нити имаће значајан утицај на ефикасност програма јер заправо неће користити сва доступна језгра у исто време.

Зашто је био потребан ГИЛ?

ЦПитхон сакупљач смећа користи ефикасну технику управљања меморијом познату као бројање референци. Ево како то функционише: Сваки објекат у питхону има број референци, који се повећава када му се додели ново име променљиве или дода у контејнер (попут туплеа, листа итд.). Слично, број референци се смањује када референца излази из опсега или када се позове израз дел. Када референтни број објекта достигне 0, прикупља се смеће и ослобођена меморија се ослобађа.

Али проблем је у томе што је променљива референтног броја склона условима трке као и свака друга глобална променљива. Да би решили овај проблем, програмери питхона одлучили су да користе глобално закључавање тумача. Друга опција је била да се сваком објекту дода закључавање што би резултирало застојима и повећањем општих трошкова од позива аццепт () и релеасе ().

Према томе, ГИЛ је значајно ограничење за вишедневне питхон програме који изводе тешке операције везане за ЦПУ (ефективно их чинећи једнонитним). Ако желите да користите више ЦПУ језгара у својој апликацији, користите вишепроцесирање уместо модула.

Резиме

  • Питхон подржава 2 модула за мултитхреадинг:
    1. __тхреад модул: Омогућава имплементацију на ниском нивоу за тхреадинг и застарио је.
    2. модул за навоје : Омогућава имплементацију на високом нивоу за вишеструку нит и тренутни је стандард.
  • Да бисте креирали нит помоћу модула за навоје, морате учинити следеће:
    1. Направите класу која проширује Тхреад класа.
    2. Замените његов конструктор (__инит__).
    3. Замени га трцати() метода.
    4. Направите објекат ове класе.
  • Нит се може извршити позивом на почетак() метода.
  • Тхе придружити() метода се може користити за блокирање других нити све док ова нит (она на којој је позвано придруживање) не заврши извршавање.
  • Услов трке се јавља када више нити приступа истовремено или мења дељени ресурс.
  • То се може избећи синхронизацијом нити.
  • Питхон подржава 6 начина за синхронизацију нити:
    1. Браве
    2. РЛоцкс
    3. Семафори
    4. Услови
    5. Догађаји, и
    6. Препреке
  • Браве дозвољавају да само одређена нит која је стекла браву уђе у критични одељак.
  • Закључавање има 2 примарна метода:
    1. стећи() : Поставља закључавање на закључан. Ако се позове на закључани објекат, блокира се све док извор није слободан.
    2. издање() : Поставља закључавање на откључан и враћа се. Ако се позове на откључани објекат, враћа фалсе.
  • Глобално закључавање тумача је механизам помоћу којег се може извршити само 1 процес тумача ЦПитхон одједном.
  • Коришћен је да олакша функцију бројања референци ЦПитхонс -овог сакупљача смећа.
  • Да бисте направили Питхон апликације са тешким операцијама везаним за ЦПУ, требало би да користите вишепроцесорски модул.