Програмски језик питхон вам омогућава употребу вишеструке обраде или вишеструког увођења. У овом упутству ћете научити како писати вишенитне апликације на Питхону.
Шта је нит?
Нит је јединица за извођење при истовременом програмирању. Мултитхреадинг је техника која омогућава ЦПУ-у да истовремено извршава многе задатке једног процеса. Ове нити могу да се извршавају појединачно док деле своје ресурсе процеса.
Шта је процес?
Процес је у основи програм у извршењу. Када покренете апликацију на рачунару (попут прегледача или уређивача текста), оперативни систем креира процес.
Шта је Мултитхреадинг у Питхону?
Вишенитност у програмирању на Питхону је добро позната техника у којој више нити у процесу дели свој простор података са главном нити, што чини дељење информација и комуникацију унутар нити лаким и ефикасним. Навоји су лакши од процеса. Више нити могу се извршавати појединачно док деле своје ресурсе процеса. Сврха мултитхреадинг-а је истодобно покретање више задатака и функцијских ћелија.
Шта је вишепроцесирање?
Вишепроцесирање вам омогућава истовремено покретање више неповезаних процеса. Ови процеси не деле своје ресурсе и комуницирају путем ИПЦ-а.
Питхон Мултитхреадинг вс Мултипроцессинг
Да бисте разумели процесе и нити, размотрите овај сценарио: .еке датотека на рачунару је програм. Када га отворите, ОС га учита у меморију, а ЦПУ га извршава. Инстанца програма који је сада покренут назива се процес.
Сваки процес ће имати 2 основне компоненте:
- Код
- Подаци
Сада процес може садржати један или више подделова који се називају нити. Ово зависи од архитектуре ОС,. Можете сматрати нит као део процеса који оперативни систем може засебно извршити.
Другим речима, то је ток инструкција које ОС може самостално да покреће. Нити унутар једног процеса деле податке о том процесу и осмишљени су тако да заједно раде на олакшавању паралелизма.
У овом упутству ћете научити,
- Шта је нит?
- Шта је процес?
- Шта је Мултитхреадинг?
- Шта је вишепроцесирање?
- Питхон Мултитхреадинг вс Мултипроцессинг
- Зашто користити Мултитхреадинг?
- Питхон МултиТхреадинг
- Модули Тхреад и Тхреадинг
- Модул навоја
- Модул навоја
- Застоји и услови трке
- Синхронизација нити
- Шта је ГИЛ?
- Зашто је био потребан ГИЛ?
Зашто користити Мултитхреадинг?
Мултитхреадинг вам омогућава да разбијете апликацију на више подзадатака и истовремено их покренете. Ако правилно користите мултитхреадинг, брзина апликације, перформансе и приказивање могу се побољшати.
Питхон МултиТхреадинг
Питхон подржава конструкције како за вишепроцесорску обраду, тако и за вишеструку обраду нити. У овом упутству ћете се првенствено усредсредити на примену вишенитних апликација са питхоном. Постоје два главна модула која се могу користити за обраду нити у Питхону:
- Нит модул, и
- Тхреадинг модул
Међутим, у питхону постоји и нешто што се назива глобална брава тумача (ГИЛ). Не дозвољава много повећања перформанси, а може чак и смањити перформансе неких мултитхреадинг апликација. Све ћете о томе научити у наредним одељцима овог водича.
Модули Тхреад и Тхреадинг
Ова два модула који ће вас научити о у овом упутству су нит модул и навоја модул .
Међутим, модул нити је дуго застарео. Почевши од Питхон 3, означен је као застарео и доступан је само као __тхреад ради повратне компатибилности.
Требали бисте користити модул навоја вишег нивоа за апликације које намеравате да примените. Модул нити овде је покривен само у образовне сврхе.
Модул навоја
Синтакса за креирање нове нити помоћу овог модула је следећа:
thread.start_new_thread(function_name, arguments)
У реду, сада сте покрили основну теорију за почетак кодирања. Дакле, отворите свој ИДЛЕ или бележницу и откуцајте следеће:
import timeimport _threaddef thread_test(name, wait):i = 0while i <= 3:time.sleep(wait)print("Running %s\n" %name)i = i + 1print("%s has finished execution" %name)if __name__ == "__main__":_thread.start_new_thread(thread_test, ("First Thread", 1))_thread.start_new_thread(thread_test, ("Second Thread", 2))_thread.start_new_thread(thread_test, ("Third Thread", 3))
Спремите датотеку и притисните Ф5 да бисте покренули програм. Ако је све урађено исправно, ово би требало да видите:
Сазнаћете више о условима трке и како се носити са њима у наредним одељцима
ОБЈАШЊЕЊЕ КОДА
- Ове изјаве увозе модул времена и нити који се користе за извршавање и одлагање Питхон нити.
- Овде сте дефинисали функцију названу тхреад_тест, која ће бити позвана методом старт_нев_тхреад . Функција покреће вхиле петљу за четири понављања и исписује име нити која ју је позвала. Када је итерација завршена, она исписује поруку у којој се каже да је нит завршила извршење.
- Ово је главни одељак вашег програма. Овде једноставно позивате методу старт_нев_тхреад са функцијом тхреад_тест као аргументом.
Ово ће створити нову нит за функцију коју проследите као аргумент и започети њено извршавање. Имајте на уму да ово (нит _ тест) можете заменити било којом другом функцијом коју желите да покренете као нит.
Модул навоја
Овај модул је имплементација навоја на високом нивоу у питхон-у и де фацто стандард за управљање вишенитним апликацијама. Пружа широк спектар функција у поређењу са модулом нити.

Ево листе неких корисних функција дефинисаних у овом модулу:
Назив функције | Опис |
ацтивеЦоунт () | Враћа тачку Опции предмета који су још увек жив |
цуррентТхреад () | Даје тренутни објекат класе Тхреад. |
набројати () | Наводи све активне Тхреад објекте. |
исДаемон () | Враћа тачно ако је нит демон. |
је жив() | Приказује тачно ако је нит још увек жива. |
Методе класе навоја | |
почетак() | Покреће активност нити. Мора се позвати само једном за сваку нит, јер ће бацити рунтиме грешку ако се позове више пута. |
трцати() | Ова метода означава активност нити и може је надјачати класа која проширује класу Тхреад. |
придружити() | Блокира извршавање другог кода док се нит на којој је метода јоин () позвана не заврши. |
Историја: класа нити
Пре него што започнете са кодирањем вишенитних програма помоћу навоја модула, пресудно је разумети класу Тхреад. Класа нити је примарна класа која дефинише предложак и операције нити у питхону.
Најчешћи начин за креирање вишенитне апликације питхон је декларација класе која проширује класу Тхреад и замењује методу рун ().
Класа Тхреад, резимеом, означава секвенцу кода која се изводи у засебној нити контроле.
Дакле, приликом писања вишенитне апликације урадићете следеће:
- дефинисати класу која проширује класу Тхреад
- Премостити __инит__ конструктор
- Замените методу рун ()
Једном када је направљен објекат нити, метода старт () се може користити за започињање извршавања ове активности, а метода јоин () може се користити за блокирање свих осталих кодова док се тренутна активност не заврши.
Покушајмо сада да користимо модул за навоја за примену вашег претходног примера. Опет, упалите свој ИДЛЕ и укуцајте следеће:
import timeimport threadingclass threadtester (threading.Thread):def __init__(self, id, name, i):threading.Thread.__init__(self)self.id = idself.name = nameself.i = idef run(self):thread_test(self.name, self.i, 5)print ("%s has finished execution " %self.name)def thread_test(name, wait, i):while i:time.sleep(wait)print ("Running %s \n" %name)i = i - 1if __name__=="__main__":thread1 = threadtester(1, "First Thread", 1)thread2 = threadtester(2, "Second Thread", 2)thread3 = threadtester(3, "Third Thread", 3)thread1.start()thread2.start()thread3.start()thread1.join()thread2.join()thread3.join()
Ово ће бити излаз када извршите горњи код:
ОБЈАШЊЕЊЕ КОДА
- Овај део је исти као и наш претходни пример. Овде увозите модул времена и нити који се користе за руковање извршавањем и кашњењем Питхон нити.
- У овом биту креирате класу која се назива тхреадтестер, која наслеђује или проширује класу Тхреад модула за навоја. Ово је један од најчешћих начина креирања нити у питхону. Међутим, требало би да замените само конструктор и метод рун () у својој апликацији. Као што видите у горњем узорку кода, метода __инит__ (конструктор) је замењена.
Слично томе, такође сте надјачали методу рун () . Садржи код који желите извршити унутар нити. У овом примеру позвали сте функцију тхреад_тест ().
- Ово је метода тхреад_тест () која узима вредност и као аргумент, смањује је за 1 на свакој итерацији и петља кроз остатак кода док и не постане 0. У свакој итерацији исписује име тренутно извршавајуће нити и спава секунде чекања (што се такође узима као аргумент).
- тхреад1 = тхреадтестер (1, „Прва нит“, 1)
Овде стварамо нит и преносимо три параметра која смо декларисали у __инит__. Први параметар је ид нити, други параметар је име нити, а трећи параметар је бројач, који одређује колико пута треба да се покрене вхиле петља.
- тхреад2.старт ()
Метод покретања користи се за покретање извођења нити. Интерно функција старт () позива методу рун () ваше класе.
- тхреад3.јоин ()
Метода јоин () блокира извршавање другог кода и чека док се нит на којој је позван не заврши.
Као што већ знате, нити које су у истом процесу имају приступ меморији и подацима тог процеса. Као резултат, ако више од једне нити покуша истовремено да измени или приступи подацима, могу се увући грешке.
У следећем одељку видећете различите врсте компликација које се могу појавити када нити приступају подацима и критичном одељку без провере постојећих приступних трансакција.
Застоји и услови трке
Пре учења о мртвим тачкама и условима трке, било би корисно разумети неколико основних дефиниција повезаних са истовременим програмирањем:
- Критични одељак
То је фрагмент кода који приступа или мења заједничке променљиве и мора се изводити као атомска трансакција.
- Пребацивање контекста
То је процес који ЦПУ следи да би сачувао стање нити пре него што пређе са једног задатка на други, тако да се касније може наставити са исте тачке.
Ћорсокаци
Застоји су најстрашније питање са којим се програмери суочавају приликом писања истовремених / вишенитних апликација у питхон-у. Најбољи начин да се разумеју ћорсокаци је коришћење класичног примера рачунарских наука, познатог као Дининг Пхилосопхерс Проблем.
Изјава проблема филозофа за ручавање је следећа:
Пет филозофа седи на округлом столу са пет тањира шпагета (врста тестенине) и пет виљушака, као што је приказано на дијаграму.

У било ком тренутку, филозоф мора или јести или размишљати.
Штавише, филозоф мора узети две суседне вилице (тј. Леву и десну виљушку) пре него што поједе шпагете. Проблем ћорсокака настаје када свих пет филозофа истовремено подигну своје десне виљушке.
Будући да сваки од филозофа има по једну виљушку, сви ће сачекати да остали одложе виљушку. Као резултат, нико од њих неће моћи да једе шпагете.
Слично томе, у истовременом систему, долази до застоја када различите нити или процеси (филозофи) покушавају да истовремено прибаве заједничке ресурсе система (вилице). Као резултат, ниједан процес нема прилику да се изврши јер чека други ресурс који држи неки други процес.
Услови трке
Стање трке је нежељено стање програма које се јавља када систем истовремено изводи две или више операција. На пример, размотрите ову једноставну фор петљу:
i=0; # a global variablefor x in range(100):print(i)i+=1;
Ако креирате н броја нити које покрећу овај код одједном, не можете одредити вредност и (коју нити деле) када програм заврши извршење. То је зато што се у стварном окружењу са вишеструким нитима нити могу преклапати, а вредност и коју је нит дохватио и изменио може се променити између тога када јој нека друга нит приступа.
Ово су две главне класе проблема који се могу појавити у мултитхреадинг или дистрибуираној питхон апликацији. У следећем одељку ћете научити како да превазиђете овај проблем синхронизацијом нити.
Синхронизација нити
За решавање услова трке, застоја и других проблема заснованих на нитима, модул за навоја омогућава објекат Лоцк . Идеја је да када нит жели приступ одређеном ресурсу, добије закључавање за тај ресурс. Једном када нит закључа одређени ресурс, ниједна друга нит му не може приступити док се брава не ослободи. Као резултат, промене ресурса ће бити атомске, а услови расе ће бити избегнути.
Брава је примитив синхронизације на ниском нивоу који имплементира модул __тхреад . У било ком тренутку брава може бити у једном од 2 стања: закључана или откључана. Подржава две методе:
- стећи()
Када је стање закључавања откључано, позивање методе аццепт () ће променити стање у закључано и вратити се. Међутим, ако је стање закључано, позив за преузимање () блокира се док нека друга нит не позове методу релеасе ().
- издање()
Метода релеасе () користи се за постављање стања на откључано, односно за отпуштање браве. Може га позвати било која нит, не нужно она која је стекла браву.
Ево примера употребе брава у апликацијама. Укључите ИДЛЕ и откуцајте следеће:
import threadinglock = threading.Lock()def first_function():for i in range(5):lock.acquire()print ('lock acquired')print ('Executing the first funcion')lock.release()def second_function():for i in range(5):lock.acquire()print ('lock acquired')print ('Executing the second funcion')lock.release()if __name__=="__main__":thread_one = threading.Thread(target=first_function)thread_two = threading.Thread(target=second_function)thread_one.start()thread_two.start()thread_one.join()thread_two.join()
Сада притисните Ф5. Требали бисте видети излаз попут овог:
ОБЈАШЊЕЊЕ КОДА
- Овде једноставно креирате нову браву позивањем фабричке функције тхреададинг.Лоцк () . Интерно Лоцк () враћа инстанцу најефикасније конкретне класе Лоцк коју одржава платформа.
- У првој изјави закључавање стичете позивањем методе аццепт (). Када се закључавање одобри, на конзолу одштампате „закључано стечено“ . Једном када се сав код за који желите да се нит изведе, заврши извршење, отпуштате закључавање позивањем методе релеасе ().
Теорија је у реду, али како знате да је брава заиста функционисала? Ако погледате излаз, видећете да се сваки испис исписује тачно по један ред. Подсетимо се да су у ранијем примеру излази из штампе били случајни јер је више нити истовремено приступало методи принт (). Овде се функција штампања позива тек након стицања браве. Дакле, излази се приказују један по један и ред по ред.
Осим брава, питхон подржава и неке друге механизме за руковање синхронизацијом нити као што је наведено у наставку:
- РЛоцкс
- Семафори
- Услови
- Догађаји и
- Баријере
Глобал Интерпретер Лоцк (и како се носити с тим)
Пре него што уђемо у детаље питхон-овог ГИЛ-а, дефинишемо неколико израза који ће бити корисни за разумевање предстојећег одељка:
- Код везан за ЦПУ: ово се односи на било који део кода који ће ЦПУ директно извршити.
- И / О-везани код: ово може бити било који код који приступа систему датотека преко ОС-а
- ЦПитхон: то је референтна имплементација Питхона и може се описати као тумач написан на Ц и Питхон (програмски језик).
Шта је ГИЛ у Питхону?
Глобал Интерпретер Лоцк (ГИЛ) у питхону је процесна брава или мутек који се користи док се баве процесима. Осигурава да једна нит истовремено може приступити одређеном ресурсу, а такође спречава употребу објеката и бајт кодова одједном. Ово користи једнонитним програмима у повећању перформанси. ГИЛ у питхону је врло једноставан и лак за имплементацију.
Брава се може користити да би се осигурало да само једна нит у одређеном тренутку има приступ одређеном ресурсу.
Једна од карактеристика Питхона је да користи глобално закључавање сваког процеса тумача, што значи да сваки процес самог питхон тумача третира као ресурс.
На пример, претпоставимо да сте написали програм за питхон који користи две нити за обављање и ЦПУ и 'И / О' операција. Када извршите овај програм, догађа се следеће:
- Питхон интерпретер креира нови процес и рађа нити
- Када нит-1 почне да се покреће, прво ће добити ГИЛ и закључати га.
- Ако тхреад-2 жели да се изврши сада, мораће да сачека пуштање ГИЛ-а чак и ако је други процесор слободан.
- Сада, претпоставимо да нит-1 чека на И / О операцију. Тренутно ће отпустити ГИЛ, а нит-2 ће га стећи.
- Након завршетка И / О операција, ако нит-1 жели да се изврши сада, мораће поново да сачека да ГИЛ буде пуштен помоћу нити-2.
Због тога, само једна нит може приступити тумачу у било ком тренутку, што значи да ће постојати само једна нит која извршава питхон код у датом тренутку.
То је у реду са једнојезгарним процесором јер би за обраду нити користио временско резање (погледајте први одељак овог водича). Међутим, у случају вишејезгрених процесора, функција везана за ЦПУ која се извршава на више нити имаће значајан утицај на ефикасност програма, јер заправо неће истовремено користити сва доступна језгра.
Зашто је био потребан ГИЛ?
ЦПитхон сакупљач смећа користи ефикасну технику управљања меморијом познату као бројање референци. Ево како то функционише: Сваки објекат у питхону има број референци, који се повећава када му се додели ново име променљиве или дода у контејнер (попут корпе, листе итд.). Слично томе, број референци се смањује када референца излази из опсега или када се позове дел израз. Када број референци објекта достигне 0, сакупља се смеће и ослобађа се додељена меморија.
Али проблем је што је променљива бројача референци склона расним условима као и свака друга глобална променљива. Да би решили овај проблем, програмери питхона одлучили су да користе глобалну браву тумача. Друга опција је била додавање браве сваком објекту што би резултирало застојима и повећаним режијским трошковима за позиве преузимања () и отпуштања ().
Због тога је ГИЛ значајно ограничење за вишенитне питхон програме који изводе тешке операције везане за ЦПУ (ефективно их чине једнонитним). Ако желите да користите више ЦПУ језгара у својој апликацији, уместо тога користите модул за вишепроцесорску обраду .
Резиме
- Питхон подржава 2 модула за мултитхреадинг:
- __тхреад модул: Обезбеђује имплементацију навоја на ниском нивоу и застарео је.
- тхреад тхреад модул : Пружа имплементацију на вишем нивоу за мултитхреадинг и тренутни је стандард.
- Да бисте креирали нит помоћу модула за навоја, морате урадити следеће:
- Направите класу која проширује класу Тхреад .
- Замени његов конструктор (__инит__).
- Замени његову методу рун () .
- Направите објекат ове класе.
- Нит се може извршити позивањем методе старт () .
- Јоин () метод може да се користи за блокирање других тема до овој теми (она на којој се придруже се звао) завршава извршење.
- Услов трке се јавља када више нити истовремено приступа или мења заједнички ресурс.
- То се може избећи синхронизацијом нити.
- Питхон подржава 6 начина за синхронизацију нити:
- Браве
- РЛоцкс
- Семафори
- Услови
- Догађаји и
- Баријере
- Браве омогућавају да само одређена нит која је стекла браву уђе у критични одељак.
- Брава има 2 примарне методе:
- придобити () : Поставља стање закључавања на закључано. Ако се позове на закључани објекат, блокира се док се ресурс не ослободи.
- релеасе () : Поставља стање закључавања на откључано и враћа се. Ако се позове на откључани објекат, враћа фалсе.
- Глобална брава тумача је механизам помоћу којег истовремено може да се изврши само 1 процес тумача ЦПитхон.
- Коришћен је за олакшавање функције бројања референци ЦПитхонс-овог сакупљача смећа.
- Да бисте направили Питхон апликације са тешким операцијама везаним за процесор, требало би да користите модул за вишепроцесорску обраду.