Pthreads Translation көмегімен PHP тілінде көп ағынды бағдарламалау. PHP-де көп ағынды есептеулер: pthreads Jedi жолы - PCNTL кеңейтімін пайдалану

Мен жақында pthreads қолданып көрдім және жағымды таң қалдым - бұл PHP-де бірнеше нақты ағындармен жұмыс істеу мүмкіндігін қосатын кеңейтім. Ешқандай эмуляция, сиқыр жоқ, жалғандық жоқ - бәрі шынайы.



Мен осындай тапсырманы қарастырып жатырмын. Жылдам орындалуы керек тапсырмалардың көптігі бар. РНР-де бұл мәселені шешуге арналған басқа да құралдар бар, олар бұл жерде айтылмаған, мақала pthreads туралы.



Жіптер дегеніміз не

Осымен болды! Жақсы, барлығы дерлік. Шынында да, ізденімпаз оқырманды ренжітетін бір жайт бар. Бұлардың ешқайсысы әдепкі опциялармен құрастырылған стандартты PHP-де жұмыс істемейді. Көп ағынды пайдалану үшін PHP жүйесінде ZTS (Zend Thread Safety) қосылған болуы керек.

PHP орнату

Келесі, ZTS бар PHP. ZTS жоқ PHP (37,65 қарсы 265,05 секунд) салыстырғанда орындалу уақытының үлкен айырмашылығына қарсы болмаңыз, мен PHP орнатуды жалпылауға тырыспадым. ZTS жоқ жағдайда, мысалы, менде XDebug қосылған.


Көріп отырғаныңыздай, 2 ағынды пайдаланған кезде бағдарламаның орындалу жылдамдығы сызықтық код жағдайына қарағанда шамамен 1,5 есе жоғары. 4 жіпті пайдаланған кезде - 3 рет.


Процессор 8 ядролы болса да, бағдарламаның орындалу уақыты 4 ағыннан көп пайдаланылған жағдайда дерлік өзгеріссіз қалғанын атап өтуге болады. Бұл менің процессорымның 4 физикалық ядросының болуымен байланысты сияқты.Түсінікті болу үшін пластинаны диаграмма түрінде бейнеледім.


Түйіндеме

PHP-де pthreads кеңейтімін қолданып, көп ағынмен өте талғампаз жұмыс істеуге болады. Бұл өнімділіктің айтарлықтай өсуін қамтамасыз етеді.

Тегтер: тегтерді қосыңыз

Кейде бір мезгілде бірнеше әрекеттерді орындау қажет болады, мысалы, бір дерекқор кестесіндегі өзгерістерді тексеру және екіншісіне өзгертулер енгізу. Оның үстіне, егер операциялардың біреуі (мысалы, өзгерістерді тексеру) көп уақытты қажет етсе, дәйекті орындау ресурстарды теңдестіруді қамтамасыз етпейтіні анық.

Мәселенің бұл түрін шешу үшін бағдарламалау көп ағынды пайдаланады - әрбір операция бөлінген ресурстар саны бар жеке ағынға орналастырылады және оның ішінде жұмыс істейді. Бұл тәсілмен барлық тапсырмалар бөлек және дербес орындалады.

PHP көп ағынды қолдамаса да, оны эмуляциялаудың бірнеше әдістері бар, олар төменде талқыланады.

1. Сценарийдің бірнеше көшірмелерін орындау – бір операцияға бір көшірме

//woman.php if (!isset($_GET["thread"])) ( system("wget ​​http://localhost/woman.php?thread=make_me_happy"); system("wget ​​http: //localhost/ woman.php?thread=make_me_rich"); ) elseif ($_GET["thread"] == "мені_бақытты") ( make_her_happy(); ) elseif ($_GET["thread"] == "me_rich" ) (басқа_бір_табыңыз( ); )

Бұл сценарийді параметрлерсіз орындаған кезде, ол қажетті функциялардың орындалуын бастайтын операция идентификаторларымен («thread=make_me_happy» және «thread=make_me_rich») автоматты түрде өзінің екі көшірмесін іске қосады.

Осылайша біз қалаған нәтижеге қол жеткіземіз - екі операция бір уақытта орындалады - бірақ бұл, әрине, көп ағынды емес, тек бір уақытта тапсырмаларды орындауға арналған балдақ.

2. Джеди жолы – PCNTL кеңейтімін пайдалану

PCNTL - бұл процестермен толық жұмыс істеуге мүмкіндік беретін кеңейтім. Басқарудан басқа, ол хабарларды жіберуді, күйді тексеруді және басымдықтарды орнатуды қолдайды. PCNTL қолданатын алдыңғы сценарий осылай көрінеді:

$pid = pcntl_fork(); if ($pid == 0) ( make_her_happy(); ) elseif ($pid > 0) ( $pid2 = pcntl_fork(); if ($pid2 == 0) (басқа_бірді табу(); ) )

Бұл өте түсініксіз көрінеді, оны жол-жол арқылы қарастырайық.

Бірінші жолда біз ағымдағы процесті «айырамыз» (шанышқы барлық айнымалылардың мәндерін сақтай отырып, процесті көшіру), оны параллель орындалатын екі процеске (ағымдағы және еншілес) бөлеміз.

Қазіргі уақытта бала немесе ана процесінде екенімізді түсіну үшін pcntl_fork функциясы бала үшін 0 мәнін және ана үшін процесс идентификаторын қайтарады. Сондықтан, екінші жолда біз $pid-ге қараймыз, егер ол нөл болса, онда біз еншілес процесте боламыз - біз функцияны орындаймыз, әйтпесе, біз анадамыз (4-жол), содан кейін біз басқа процесс жасаймыз және тапсырманы бірдей орындаңыз.

Сценарийдің орындалу процесі:

Осылайша, сценарий оның көшірмелері болып табылатын және ұқсас мәндері бар бірдей айнымалыларды қамтитын тағы 2 еншілес процесті жасайды. Және pcntl_fork функциясымен қайтарылған идентификаторды пайдалана отырып, біз қазіргі уақытта қандай ағында екенімізді анықтаймыз және қажетті әрекеттерді орындаймыз.

РНР әзірлеушілері конкуррентті сирек пайдаланатын сияқты. Мен синхронды кодтың қарапайымдылығы туралы айтпаймын; бір ағынды бағдарламалау, әрине, қарапайым және түсінікті, бірақ кейде параллелизмді аздап пайдалану өнімділікті айтарлықтай арттыруға әкелуі мүмкін.

Бұл мақалада біз pthreads кеңейтімін пайдаланып PHP-де көп ағынды қалай алуға болатынын қарастырамыз. Бұл орнатылған PHP 7.x нұсқасының ZTS (Zend Thread Safety) нұсқасын және орнатылған pthreads v3 кеңейтімін қажет етеді. (Жазу кезінде PHP 7.1-де пайдаланушылар pthreads репозиторийіндегі негізгі тармақтан орнатуы керек - үшінші тарап кеңейтімін қараңыз.)

Кішігірім түсініктеме: pthreads v2 PHP 5.x үшін арналған және енді ол қолдау көрсетілмейді, pthreads v3 PHP 7.x үшін және белсенді түрде әзірленуде.

Осындай шегіністерден кейін сөзге тікелей көшейік!

Бір реттік тапсырмаларды өңдеу

Кейде бір реттік тапсырмаларды көп ағынды жолмен өңдегіңіз келеді (мысалы, кейбір енгізу/шығарумен байланысты тапсырманы орындау). Мұндай жағдайларда жаңа ағын жасау үшін Thread сыныбын пайдалануға және бөлек ағында кейбір өңдеуді орындауға болады.

Мысалы:

$тапсырма = жаңа сынып Тақырыпты кеңейтеді (жеке $жауап; жалпы функцияны іске қосу() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+)~", $content, $матчтар); $this->жауап = $матчтар; ) ); $task->start() && $task->join(); var_dump($task->response); // жол (6) "Google"

Мұнда іске қосу әдісі жаңа ағынның ішінде орындалатын біздің өңдеуіміз болып табылады. Thread::start шақырылғанда, жаңа ағын пайда болады және іске қосу әдісі шақырылады. Содан кейін біз еншілес ағынды Thread::join шақыру арқылы негізгі ағынға қайта қосамыз, ол еншілес ағынның орындалуын аяқтағанша блоктайды. Бұл нәтижені басып шығару әрекетінен бұрын тапсырманың орындалуын аяқтайтынына кепілдік береді (ол $task->response ішінде сақталады).

Сыныпты ағын логикасына байланысты қосымша жауапкершіліктермен (соның ішінде іске қосу әдісін анықтау жауапкершілігімен) ластау қажет болмауы мүмкін. Біз мұндай класстарды Threaded класынан мұраға алу арқылы ажырата аламыз. Содан кейін оларды басқа ағынның ішінде іске қосуға болады:

Сынып тапсырмасы Threaded ( public $response; public function someWork() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+) ~", $content, $матчтар); $ this->жауап = $сәйкестік; ) ) $тапсырма = жаңа тапсырма; $thread = new class($task) Thread кеңейтеді ( private $task; public function __construct(Threaded $task) ( $this->task = $task; ) public function run() ( $this->task->someWork() );))) $thread->start() && $thread->join(); var_dump($тапсырма->жауап);

Бөлек ағында іске қосылуы қажет кез келген сынып міндетті Threaded сыныбынан мұра алады. Себебі ол әртүрлі ағындарда өңдеуді орындау үшін қажетті мүмкіндіктерді, сонымен қатар жасырын қауіпсіздік пен пайдалы интерфейстерді (ресурстарды синхрондау сияқты) қамтамасыз етеді.

pthreads кеңейтімі ұсынатын класс иерархиясын қарастырайық:

Бұрандалы (өткізілетін, жиналатын) жіп жұмысшысының ұшпа пулы

Біз Thread және Threaded сыныптарының негіздерін қарастырып, үйрендік, енді қалған үшеуін (Жұмысшы, Ұшқыш және Пул) қарастырайық.

Жіптерді қайта пайдалану

Параллельдеуді қажет ететін әрбір тапсырма үшін жаңа ағынды бастау өте қымбат. Себебі, PHP ішінде көп ағындылыққа қол жеткізу үшін pthreads ішінде жалпы ештеңе жоқ архитектураны іске асыру қажет. Бұл PHP интерпретаторының ағымдағы данасы (соның ішінде әрбір класс, интерфейс, белгі және функция) барлық орындалу мәтінмәні жасалған әрбір ағын үшін көшірілуі керек дегенді білдіреді. Бұл айтарлықтай өнімділікке әсер ететіндіктен, ағынды әрқашан мүмкіндігінше қайта пайдалану керек. Ағындарды екі жолмен қайта пайдалануға болады: Жұмысшыларды пайдалану немесе Пулдарды пайдалану.

Жұмысшы класы басқа ағында бірнеше тапсырмаларды синхронды түрде орындау үшін пайдаланылады. Бұл жаңа Worker данасын жасау (жаңа ағынды жасайтын), содан кейін тапсырмаларды сол бөлек ағынның стегіне итеру (Worker::stack көмегімен) арқылы орындалады.

Міне, шағын мысал:

Сынып тапсырмасы Threaded (жеке $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Tsk: ($this->value)" кеңейтеді. \n"; ) ) $жұмысшы = жаңа жұмысшы(); $worker->start(); үшін ($i = 0; $i стек(жаңа тапсырма($i)); ) while ($жұмысшы->жинау()); $worker->shutdown();

Жоғарыда келтірілген мысалда жаңа $worker нысанына арналған 15 тапсырма Worker::stack әдісі арқылы стекке итеріледі, содан кейін олар итерілген ретпен өңделеді. Жоғарыда көрсетілгендей Worker::collect әдісі тапсырмаларды орындау аяқтала салысымен оларды тазалау үшін қолданылады. Оның көмегімен уақытша цикл ішінде біз Worker::shutdown деп атамас бұрын, стектегі барлық тапсырмалар орындалып, тазартылғанша негізгі ағынды блоктаймыз. Жұмысшыны мерзімінен бұрын тоқтату (яғни, әлі де аяқталуы қажет тапсырмалар болған кезде) барлық тапсырмалар орындалу аяқталғанша негізгі ағынды блоктайды, тек тапсырмалар қоқыс жиналмайды (бұл жадтың ағып кетуін білдіреді).

Жұмысшы сыныбы өзінің тапсырмалар стекіне қатысты бірнеше басқа әдістерді қамтамасыз етеді, соның ішінде соңғы жинақталған тапсырманы жоюға арналған Worker::unstack және орындалу стекіндегі тапсырмалар санын алу үшін Worker::getStacked. Жұмысшы стекінде орындалуы қажет тапсырмалар ғана бар. Стектегі тапсырма орындалғаннан кейін ол жойылады және қоқыс жинауға арналған бөлек (ішкі) стекке орналастырылады (Жұмысшы:: жинау әдісі арқылы).

Бірнеше тапсырмалар бойынша ағынды қайта пайдаланудың тағы бір жолы - ағын пулын пайдалану (Пул сыныбы арқылы). Ағын пулы орындалатын тапсырмаларды қосу үшін Жұмысшылар тобын пайдаланады бір мезгілде, онда пул жасалған кезде параллельдік коэффициенті (ол жұмыс істейтін пул ағындарының саны) орнатылады.

Жоғарыдағы мысалды жұмысшылар пулын пайдалану үшін бейімдеп көрейік:

Сынып тапсырмасы Threaded (жеке $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Tsk: ($this->value)" кеңейтеді. \n"; ) ) $пул = жаңа Пул(4); for ($i = 0; $i submit(new Task($i)); ) while ($pool->collect()); $пул->өшіру();

Жұмысшыға қарағанда бассейнді пайдалану кезінде бірнеше елеулі айырмашылықтар бар. Біріншіден, пулды қолмен іске қосудың қажеті жоқ; ол қол жетімді болған кезде тапсырмаларды орындауды бастайды. Екіншіден, біз жіберуемес, бассейнге тапсырмалар оларды стекке қойыңыз. Сонымен қатар, Pool класы Threaded жүйесінен мұраланбайды, сондықтан басқа ағындарға (Жұмысшыдан айырмашылығы) берілмейді.

Жұмысшылар мен бассейндердің тапсырмаларын орындағаннан кейін тез арада тазалау, содан кейін оларды өздері қолмен аяқтау жақсы тәжірибе. Thread сыныбы арқылы жасалған ағындар да негізгі ағынға тіркелуі керек.

pthreads және (im)өзгергіштік

Біз қозғайтын соңғы сынып - бұл ұшқыш, pthreads v3 үшін жаңа қосымша. Өзгермейтіндік pthreads маңызды тұжырымдамаға айналды, өйткені онсыз өнімділік айтарлықтай төмендейді. Сондықтан, әдепкі бойынша, өздері Threaded нысандары болып табылатын Threaded сыныптарының сипаттары енді өзгермейді, сондықтан оларды бастапқы тағайындаудан кейін қайта жазу мүмкін емес. Қазіргі уақытта мұндай сипаттар үшін айқын өзгергіштік қолайлы және оны жаңа Ұшқыш класын пайдалану арқылы әлі де қол жеткізуге болады.

Жаңа өзгермейтін шектеулерді көрсететін мысалды қарастырайық:

Сынып тапсырмасы Threaded файлын кеңейтеді // Threaded класы ( жалпы функция __construct() ( $this->data = new Threaded(); // $this->деректер қайта жазылмайды, себебі ол Threaded класының Threaded қасиеті болып табылады ) ) $task = new class(new Task()) Thread кеңейтеді ( // Threaded класы, себебі Thread кеңейтілген Threaded жалпы функциясы __construct($tm) ( $this->threadedMember = $tm; var_dump($this->threadedMember-> data); // object(Threaded)#3 (0) () $this->threadedMember = new StdClass(); // жарамсыз, себебі сипат Threaded класының Threaded мүшесі болып табылады ) );

Екінші жағынан, тұрақсыз класстардың бұрандалы қасиеттері өзгермелі:

Сынып тапсырмасы Ұшқышты кеңейтеді (қоғамдық функция __construct() ( $this->data = new Threaded(); $this->data = new StdClass(); // жарамды, өйткені біз тұрақсыз сыныптамыз ) ) $task = new class(new Task()) Thread кеңейтеді (қоғамдық функция __construct($vm) ( $this->volatileMember = $vm; var_dump($this->volatileMember->data); // object(stdClass)#4 (0) () // әлі жарамсыз, өйткені Volatile кеңейтілген Threaded, сондықтан сипат әлі де Threaded класының Threaded мүшесі болып табылады $this->volatileMember = new StdClass(); ) );

Біз Volatile класы Threaded сипаттарын өзгерту мүмкіндігін (сонымен қатар unset()) қамтамасыз ету үшін негізгі Threaded класы жүктеген өзгермейтіндікті қайта анықтайтынын көреміз.

Өзгергіштік және өзгергіштік класы - массивтер тақырыбын қамтитын тағы бір талқылау тақырыбы бар. Pthreads ішінде массивтер Threaded класының сипатына тағайындалған кезде автоматты түрде Тұрақты нысандарға шығарылады. Себебі, бірнеше РНР контексттерінің массивін өңдеу қауіпсіз емес.

Кейбір нәрселерді жақсырақ түсіну үшін тағы бір мысалды қарастырайық:

$массив =; $tsk = new class($array) Thread (жеке $деректер; public function __construct(array $array)) ( $this->data = $array; ) public function run() ( $this->data = 4; $) this->data = 5; print_r($this->data); ) ); $task->start() && $task->join(); /* Шығару: өзгермелі нысан ( => 1 => 2 => 3 => 4 => 5) */

Біз тұрақсыз нысандарды массив сияқты өңдеуге болатынын көреміз, себебі олар (жоғарыда көрсетілгендей) subset() операторы сияқты массив операцияларын қолдайды. Дегенмен, өзгермелі сыныптар array_pop және array_shift сияқты негізгі массив функцияларын қолдамайды. Оның орнына Threaded класы бізге кірістірілген әдістер сияқты операцияларды береді.

Демонстрация ретінде:

$мәліметтер = жаңа сынып Ұшқышты кеңейтеді (қоғамдық $a = 1; жалпы $b = 2; жалпы $c = 3; ); var_dump($деректер); var_dump($data->pop()); var_dump($деректер->shift()); var_dump($деректер); /* Шығару: object(class@anonymous)#1 (3) ( ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ) int(3) int(1) нысаны(сынып@анонимді)#1 (1) (["b"]=> int(2) ) */

Басқа қолдау көрсетілетін операцияларға Threaded::chunk және Threaded::merge кіреді.

Синхрондау

Осы мақаланың соңғы бөлімінде біз pthreads синхрондауды қарастырамыз. Синхрондау - ортақ ресурстарға қол жеткізуді басқаруға мүмкіндік беретін әдіс.

Мысалы, қарапайым есептегішті іске асырайық:

$counter = жаңа сыныпты кеңейтеді Thread ( public $i = 0; public function run() ( for ($i = 0; $i i; ) ) ); $counter->start(); үшін ($i = 0; $i i; ) $counter->join(); var_dump($counter->i); // 10-нан 20-ға дейінгі санды басып шығарады

Синхронизацияны қолданбай шығу детерминирленген емес. Бірнеше ағындар бір айнымалыға басқарылатын қатынассыз жазады, яғни жаңартулар жоғалады.

Уақытты қосу арқылы 20-ның дұрыс нәтижесін алу үшін мұны түзетейік:

$counter = жаңа сынып Thread кеңейтеді ( public $i = 0; public function run() ( $this->синхрондалған(функция () (үшін ($i = 0; $i i; ) ); ) ); $counter->start(); $counter->синхрондалған(функция ($counter) (үшін ($i = 0; $i i; ) ), $counter); $counter->join(); var_dump($counter->i); // int(20)

Синхрондалған код блоктары Threaded::wait және Threaded::notify (немесе Threaded::notifyAll) әдістерін пайдаланып бір-бірімен байланыса алады.

Мұнда екі синхрондалған while цикліндегі балама өсім берілген:

$counter = жаңа сыныпты кеңейтеді Thread ( public $cond = 1; public function run() ( $this->синхрондалған(функция () ( for ($i = 0; $i notify(); if ($this->cond) === 1) ( $this->cond = 2; $this->wait(); ) ))) ); ) ); $counter->start(); $counter->synchronized(функция ($counter) ( if ($counter->cond !== 2) ( $counter->wait(); // бірінші басталуын күтіңіз ) үшін ($i = 10; $i notify(); if ($counter->cond === 2) ( $counter->cond = 1; $counter->wait(); ) ) ), $counter); $counter->join(); /* Шығару: int(0) int(10) int(1) int(11) int(2) int(12) int(3) int(13) int(4) int(14) int(5) int( 15) int(6) int(16) int(7) int(17) int(8) int(18) int(9) int(19) */

Threaded::wait қоңырауының айналасында орналастырылған қосымша шарттарды байқауыңыз мүмкін. Бұл шарттар өте маңызды, себебі олар синхрондалған кері шақыруды ол хабарландыру алған кезде және көрсетілген шарт ақиқат болғанда жалғастыруға мүмкіндік береді. Бұл маңызды, себебі хабарландырулар Threaded::notify шақырылғаннан басқа жерлерден келуі мүмкін. Осылайша, Threaded::wait әдісіне шақырулар шарттарға қосылмаған болса, біз орындаймыз жалған ояту қоңыраулары, бұл болжаусыз код әрекетіне әкеледі.

Қорытынды

Біз pthreads бумасының бес класын (Threaded, Thread, Worker, Volatile және Pool) және әрбір сыныптың қалай қолданылатынын қарастырдық. Біз сондай-ақ pthreads-тегі өзгермейтіндіктің жаңа тұжырымдамасын қарастырдық және қолдау көрсетілетін синхрондау мүмкіндіктеріне қысқаша шолу жасадық. Осы негіздерді орындай отырып, біз енді нақты әлем жағдайларында pthreads қалай пайдалануға болатынын қарастыра бастай аламыз! Бұл келесі жазбамыздың тақырыбы болмақ.

Келесі жазбаның аудармасы сізді қызықтырса, маған хабарлаңыз: әлеуметтік желіде пікір қалдырыңыз. желілерде дауыс беріп, жазбаны әріптестеріңізбен және достарыңызбен бөлісіңіз.

  • Бағдарламалау,
  • Параллель программалау
  • Мен жақында pthreads қолданып көрдім және жағымды таң қалдым - бұл PHP-де бірнеше нақты ағындармен жұмыс істеу мүмкіндігін қосатын кеңейтім. Ешқандай эмуляция, сиқыр жоқ, жалғандық жоқ - бәрі шынайы.



    Мен осындай тапсырманы қарастырып жатырмын. Жылдам орындалуы керек тапсырмалардың көптігі бар. РНР-де бұл мәселені шешуге арналған басқа да құралдар бар, олар бұл жерде айтылмаған, мақала pthreads туралы.



    Жіптер дегеніміз не

    Осымен болды! Жақсы, барлығы дерлік. Шынында да, ізденімпаз оқырманды ренжітетін бір жайт бар. Бұлардың ешқайсысы әдепкі опциялармен құрастырылған стандартты PHP-де жұмыс істемейді. Көп ағынды пайдалану үшін PHP жүйесінде ZTS (Zend Thread Safety) қосылған болуы керек.

    PHP орнату

    Келесі, ZTS бар PHP. ZTS жоқ PHP (37,65 қарсы 265,05 секунд) салыстырғанда орындалу уақытының үлкен айырмашылығына қарсы болмаңыз, мен PHP орнатуды жалпылауға тырыспадым. ZTS жоқ жағдайда, мысалы, менде XDebug қосылған.


    Көріп отырғаныңыздай, 2 ағынды пайдаланған кезде бағдарламаның орындалу жылдамдығы сызықтық код жағдайына қарағанда шамамен 1,5 есе жоғары. 4 жіпті пайдаланған кезде - 3 рет.


    Процессор 8 ядролы болса да, бағдарламаның орындалу уақыты 4 ағыннан көп пайдаланылған жағдайда дерлік өзгеріссіз қалғанын атап өтуге болады. Бұл менің процессорымның 4 физикалық ядросының болуымен байланысты сияқты.Түсінікті болу үшін пластинаны диаграмма түрінде бейнеледім.


    Түйіндеме

    PHP-де pthreads кеңейтімін қолданып, көп ағынмен өте талғампаз жұмыс істеуге болады. Бұл өнімділіктің айтарлықтай өсуін қамтамасыз етеді.

    Тегтер:

    • php
    • жіптер
    Тегтерді қосыңыз

    Мен жақында pthreads қолданып көрдім және жағымды таң қалдым - бұл PHP-де бірнеше нақты ағындармен жұмыс істеу мүмкіндігін қосатын кеңейтім. Ешқандай эмуляция, сиқыр жоқ, жалғандық жоқ - бәрі шынайы.



    Мен осындай тапсырманы қарастырып жатырмын. Жылдам орындалуы керек тапсырмалардың көптігі бар. РНР-де бұл мәселені шешуге арналған басқа да құралдар бар, олар бұл жерде айтылмаған, мақала pthreads туралы.



    Жіптер дегеніміз не

    Осымен болды! Жақсы, барлығы дерлік. Шынында да, ізденімпаз оқырманды ренжітетін бір жайт бар. Бұлардың ешқайсысы әдепкі опциялармен құрастырылған стандартты PHP-де жұмыс істемейді. Көп ағынды пайдалану үшін PHP жүйесінде ZTS (Zend Thread Safety) қосылған болуы керек.

    PHP орнату

    Келесі, ZTS бар PHP. ZTS жоқ PHP (37,65 қарсы 265,05 секунд) салыстырғанда орындалу уақытының үлкен айырмашылығына қарсы болмаңыз, мен PHP орнатуды жалпылауға тырыспадым. ZTS жоқ жағдайда, мысалы, менде XDebug қосылған.


    Көріп отырғаныңыздай, 2 ағынды пайдаланған кезде бағдарламаның орындалу жылдамдығы сызықтық код жағдайына қарағанда шамамен 1,5 есе жоғары. 4 жіпті пайдаланған кезде - 3 рет.


    Процессор 8 ядролы болса да, бағдарламаның орындалу уақыты 4 ағыннан көп пайдаланылған жағдайда дерлік өзгеріссіз қалғанын атап өтуге болады. Бұл менің процессорымның 4 физикалық ядросының болуымен байланысты сияқты.Түсінікті болу үшін пластинаны диаграмма түрінде бейнеледім.


    Түйіндеме

    PHP-де pthreads кеңейтімін қолданып, көп ағынмен өте талғампаз жұмыс істеуге болады. Бұл өнімділіктің айтарлықтай өсуін қамтамасыз етеді.



    
    Жоғарғы