Pthreads Translation ашиглан PHP хэл дээр олон урсгалтай програмчлал. Та согтуу үедээ ямар үйлдлээсээ маш их ичиж байна вэ? Нэг удаагийн даалгаврыг боловсруулж байна

💖 Танд таалагдаж байна уу?Холбоосыг найзуудтайгаа хуваалцаарай
ЗҮРХНИЙ НЕВРОЗ (кардиофоби). Үймээн самууны синдромтой хамт фобийн онцгой хэлбэр нь кардиофоби бөгөөд үүнийг эмнэлзүйн онцлог шинж чанар, мэдэгдэхүйц давтамжаас шалтгаалан тайлбарлах ёстой. Энэ нь ихэвчлэн залуу хүмүүст, ихэвчлэн эрэгтэйчүүдэд, мөн хүүхдүүдэд тохиолддог.

Өвчтөн зүрхний үйл ажиллагаа зогсох, үхэхээс айдаг пароксизмийн түгшүүртэй байдал нь соматик өвчингүйгээр тохиолдож болно. Дараагийн дайралтын эхэн үед дотор муухайрах, толгой эргэх, дотоод сэтгэлийн түгшүүр, зүрхний бага зэрэг шахалт илэрдэг.

Гэсэн хэдий ч ихэнх тохиолдолд ямар ч сэрэмжлүүлэггүйгээр хүнд хэлбэрийн дайралт үүсдэг: зүрхний хүчтэй цохилт бүх биеэр мэдрэгдэх, цусны даралт бага зэрэг нэмэгдэх, зүрхний бүсэд хүчтэй шахаж, чангарах мэдрэмж, амьсгал давчдах, хөлрөх, толгой эргэх, ухаан алдах мэдрэмж (гэхдээ ухаан алдах биш), бүх биеийг чичрэх, энгийн айдас. Өвчтөн секундын дотор зүрх нь зогсч, үхэх болно гэдэгт итгэдэг. Энэ бол өөрийгөө устгах, үхэх айдас юм. Маш их сэтгэл хөдөлсөн үед өвчтөнүүд гүйж, тусламж гуйдаг. Хэрэв машинд явж байхдаа айдас довтолж байвал өвчтөн зогсоож, завсарлага авахаас өөр аргагүй болдог.

Эхний халдлагын дараа фобикийн хөгжил үүсдэг. Өвчтөнүүд сэтгэцийн тэнцвэрээ алдаж, байнгын айдастай амьдарч, дараагийн халдлага эсвэл үхлийг хүлээж, айдас (хүлээлтийн айдас, фоби) мэдрэмжийг мэдэрдэг. Үүний зэрэгцээ зүрхний хэвийн үйл ажиллагааны талаар эмчийн хэлсэн үг ч, өмнөх дайралтууд нь үр дагавартай байсан гэсэн итгэл үнэмшил ч тэдэнд тус болохгүй. Довтолгооны давтамж ба тэдгээрийн хоорондын зай тогтмол бус байна. Интервалтайгаар өвчтөн зүрхнийхээ үйл ажиллагааг сайтар хянаж, импульсийг хянаж, түүний өчүүхэн хазайлтыг бүртгэдэг. Тэрээр санамсаргүй экстрасистолуудыг найдваргүй үр дагавартай өвчний маргаангүй шинж тэмдэг гэж үздэг.

Өвчтөнүүд бусад ургамлын илрэлүүд, түүнчлэн тэдний сайн сайхан байдлын бага зэрэг хэлбэлзлийг болгоомжтой ажигладаг. Өвчтөнүүд өөрсдийгөө халамжилж, алхаж зүрхлэхгүй, дайралтаас урьдчилан сэргийлэхийн тулд бүх стресс, санаа зовнил, хамгийн түрүүнд хүнд хэцүү нөхцөл байдлыг арилгахыг хичээдэг. Ихэнх тохиолдолд үхлээс айх айдас, айдас, айдас төрүүлэх айдас улам бүр нэмэгддэг.

ГАРАХ НӨХЦӨЛ. Кардиофобикийн анхны дайралтын шалтгаан нь ихэвчлэн хурц зөрчилдөөн, хэт ачаалал, салах, урам хугарах, ганцаардах, хаягдах нөхцөл байдал, түүнчлэн ойр дотны хэн нэгний зүрхний үхэлд хүргэх сэтгэлийн түгшүүр юм.

Зүрхний үхэл нь залуу, эрүүл ч гэсэн үргэлж тохиолддог гэдгийг мэдэх нь санаа зовоосон хүчин зүйл болдог. Кофе, никотиныг эрчимтэй хэрэглэх нь энэ үйл явцыг өдөөж болно. Эхлэл нь ихэвчлэн бага наснаасаа эхэлдэг. Ихэнхдээ эелдэг, хараат хүүхдүүд өртдөг бөгөөд эхээс илт хамааралтай, ихэвчлэн хоёрдмол хандлагатай байдаг: нэг талаас хайрыг хүлээх, түрэмгий түлхэлтээр тусгаар тогтнох хүсэл, нөгөө талаас харшилтай, эсрэг тэсрэг уран зөгнөл. тусгаарлах. Ийм хандлага нь харилцаа холбоо тасарч, салах, урам хугарах үед онцгой аюултай. Кардиофоб нь үүнийг хүсч байгаагаа ухаарч, үүнээс айдаг болохоосоо өмнө салах айдастай амьдардаг. Эцэг эхтэйгээ хамтарсан асуудал, түншүүдтэйгээ зөрчилдөөн байнга гардаг.

ЭМЧИЛГЭЭ
Хэрэв цочмог нөхцөлд эмчтэй зөвлөлдөх, түүнтэй ярилцах нь сайжрахгүй бол тайвшруулах эм эсвэл бета хориглогчийг зааж өгнө. Айдастай мэдрэлийн өвчтэй бусад өвчтөнүүдийн нэгэн адил олон фобикүүд архины тусламжтайгаар өөрийгөө эмчлэхийг хичээдэг; гэхдээ үр нөлөө нь хангалтгүй, архинаас хамааралтай болох аюул их байна. Эмийн эмчилгээ нь зөвхөн цочмог тохиолдлын үед туслах хэрэгсэл, түүнчлэн анхны үр дүнтэй эмчилгээ юм.

Сэтгэл заслын эмчилгээ шийдвэрлэх үүрэгтэй. Энэ нь эрт эхлэх тусам сайн. Эхний кардиофобик халдлагын дараа нэн даруй шалтгаан, зөрчилдөөний нөхцөл байдлыг судлах нь дараагийн фобик хөгжлийг зогсоож чадна. Дараа нь эмчилгээ нь илүү хэцүү бөгөөд удаан хугацааны сэтгэлзүйн эмчилгээ шаардлагатай байдаг.

Эдгээр болон бусад түгшүүрийн эмгэгийн хувьд зан үйлийн эмчилгээ (сөргөлдөөн, танин мэдэхүйн эмчилгээ, өөртөө итгэх итгэлийн сургалт) онцгой заалттай байдаг. Түгшүүрээс зайлсхийх сургалтын нэг онцлог шинж чанар нь мэдрэмжгүйжүүлэх загвар дээр (өдөр тутмын нөхцөл байдлын тохирох нөхцөлд) ажилладаг бөгөөд сэтгэлийн түгшүүртэй тэмцэх сургалт нь фобик нөхцөл байдалд (үер) албадан дүрэх, даван туулах стратегийг бий болгоход ашигладаг. Хүнд хэлбэрийн түгшүүрийн эмгэг нь сэтгэлзүйн эмчилгээний янз бүрийн загварыг ашиглан эмнэлзүйн эмчилгээ шаарддаг.

PHP хөгжүүлэгчид concurrency-ийг ховор ашигладаг бололтой. Синхрон кодын энгийн байдлын талаар би ярихгүй; нэг урсгалтай програмчлал нь мэдээжийн хэрэг илүү энгийн бөгөөд ойлгомжтой боловч заримдаа параллелизмыг бага зэрэг ашиглах нь гүйцэтгэлийг мэдэгдэхүйц нэмэгдүүлэх болно.

Энэ нийтлэлд бид pthreads өргөтгөлийг ашиглан PHP хэл дээр хэрхэн multithreading хийж болох талаар авч үзэх болно. Үүний тулд PHP 7.x-ийн ZTS (Zend Thread Safety) хувилбарыг суулгасан pthreads v3 өргөтгөлийн хамт суулгасан байх шаардлагатай. (Бичиж байх үед PHP 7.1 дээр хэрэглэгчид pthreads репозитор дахь мастер салбараас суулгах шаардлагатай болно - гуравдагч талын өргөтгөлийг үзнэ үү.)

Жижигхэн тодруулга: pthreads v2 нь PHP 5.x-д зориулагдсан бөгөөд цаашид дэмжигдэхгүй, pthreads v3 нь PHP 7.x-д зориулагдсан бөгөөд идэвхтэй хөгжиж байна.

Ийм ухралт хийсний дараа шууд асуудал руугаа орцгооё!

Нэг удаагийн даалгаврыг боловсруулж байна

Заримдаа та нэг удаагийн даалгаврыг олон урсгалтай аргаар (жишээ нь, зарим I/O-тэй холбоотой ажлыг гүйцэтгэх) боловсруулахыг хүсдэг. Ийм тохиолдолд та Thread классыг ашиглан шинэ хэлхээ үүсгэж, тусдаа thread дээр зарим боловсруулалт хийж болно.

Жишээлбэл:

$даалгавар = шинэ анги нь Thread-ыг өргөтгөх (хувийн $response; нийтийн функцийг ажиллуулах() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+)~", $ контент, $ таарч байна); $ this->response = $ matches; ) ); $task->start() && $task->join(); var_dump($task->response); // string (6) "Google"

Энд ажиллуулах арга бол бидний боловсруулалт бөгөөд үүнийг шинэ урсгал дотор гүйцэтгэх болно. Thread::start дуудагдах үед шинэ урсгал үүсч, run method дуудагдана. Дараа нь бид Thread::join гэж дуудаж, хүүхэд хэлхээг үндсэн хэлхээнд буцааж нэгтгэх бөгөөд энэ нь хүүхэд хэлхээг гүйцэтгэж дуусах хүртэл хаах болно. Энэ нь үр дүнг хэвлэхийг оролдохоос өмнө ($task->response-д хадгалагдсан) даалгаврыг гүйцэтгэж дуусахыг баталгаажуулдаг.

Урсгалын логиктой холбоотой нэмэлт үүрэг хариуцлагыг (гүйлтийн аргыг тодорхойлох үүрэг гэх мэт) ангиллаар бохирдуулах нь тийм ч таатай биш байж болох юм. Бид Threaded ангиас удамшсанаар ийм ангиудыг ялгаж чадна. Дараа нь тэдгээрийг өөр thread дотор ажиллуулж болно:

Ангийн даалгавар нь Threaded ( нийтийн $response; public function someWork() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+) ~", $content, $match); $ 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 өргөтгөлийн санал болгож буй ангийн шатлалыг харцгаая:

Threaded (Traversable, Collectable-ийг хэрэгжүүлдэг) Thread Worker Volatile Pool

Бид Thread болон Threaded ангиудын үндсийг аль хэдийн үзэж, сурсан, одоо бусад гурвыг (Ажилчин, Дэгдэмхий, Усан сан) харцгаая.

Threads дахин ашиглах

Зэрэгцүүлэх шаардлагатай ажил бүрийн хувьд шинэ хэлхээ эхлүүлэх нь нэлээд үнэтэй байдаг. Учир нь PHP дотор олон урсгалтай болгохын тулд нийтлэг-юу ч биш архитектурыг pthread-д хэрэгжүүлэх ёстой. Энэ нь PHP орчуулагчийн одоогийн жишээний гүйцэтгэх контекстийг бүхэлд нь (анги, интерфейс, шинж чанар, функц бүрийг оруулаад) үүсгэсэн хэлхээ бүрд хуулах ёстой гэсэн үг юм. Энэ нь гүйцэтгэлд мэдэгдэхүйц нөлөө үзүүлдэг тул аль болох урсгалыг дахин ашиглах хэрэгтэй. Threads-ийг хоёр аргаар дахин ашиглаж болно: Workers эсвэл Pools ашиглах.

Worker анги нь өөр thread дотор хэд хэдэн ажлыг синхроноор гүйцэтгэхэд ашиглагддаг. Энэ нь шинэ Worker жишээ үүсгээд (шинэ хэлхээ үүсгэдэг), дараа нь тухайн тусдаа хэлхээний стек рүү даалгавруудыг түлхэж (Worker::stack ашиглан) хийдэг.

Энд жижиг жишээ байна:

Ангийн даалгавар нь Threaded ( private $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $ажилчин = шинэ Ажилчин(); $ажилчин->эхлэх(); for ($i = 0; $i stack(new Task($i)); ) while ($worker->collect()); $worker->sutdown();

Дээрх жишээнд шинэ $worker объектын 15 даалгаврыг Worker::stack аргаар стек рүү түлхэж, дараа нь түлхэж өгсөн дарааллаар нь боловсруулдаг. Дээр үзүүлсэн шиг Worker::collect аргыг даалгавруудыг гүйцэтгэж дуусмагц цэвэрлэхэд ашигладаг. Үүний тусламжтайгаар бид Worker::shutdown гэж дуудахаас өмнө стек дээрх бүх ажлуудыг хийж дуусгах хүртэл хэсэг хугацааны давталт дотор үндсэн утсыг блоклодог. Ажилтныг эрт дуусгах нь (өөрөөр хэлбэл дуусгах шаардлагатай ажлууд байсаар байхад) бүх ажлуудыг дуусгах хүртэл үндсэн хэлхээг блоклосон хэвээр байх болно, зөвхөн даалгаварууд нь хог хаягдлыг цуглуулахгүй (энэ нь санах ойн алдагдалд хүргэдэг).

Worker анги нь ажлын стектэй холбоотой өөр хэд хэдэн аргуудыг хангадаг бөгөөд үүнд хамгийн сүүлийн давхарласан даалгаврыг устгах Worker::unstack, гүйцэтгэлийн стек дэх даалгаврын тоог авах Worker::getStacked орно. Ажилчдын стек нь зөвхөн гүйцэтгэх ёстой ажлуудыг агуулдаг. Стек дээрх ажил дууссаны дараа түүнийг салгаж, хог цуглуулах тусдаа (дотоод) стек дээр байрлуулна (Ажилчин:: цуглуулах аргыг ашиглан).

Thread-ийг олон даалгаварт дахин ашиглах өөр нэг арга бол thread-ийн санг ашиглах явдал юм (Pool классаар). Thread pool нь даалгавруудыг гүйцэтгэхийн тулд ажилчдын бүлгийг ашигладаг нэгэн зэрэг, цөөрөм үүсгэх үед зэрэгцээ байдлын коэффициентийг (үүнтэй ажилладаг усан сангийн хэлхээний тоо) тохируулдаг.

Ажилчдын нөөцийг ашиглахын тулд дээрх жишээг тохируулъя.

Ангийн даалгавар нь Threaded ( private $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $pool = new Pool(4); for ($i = 0; $i submit(new Task($i)); ) while ($pool->collect()); $pool->sutdown();

Усан санг ашиглахдаа ажилчдаас ялгаатай хэд хэдэн мэдэгдэхүйц ялгаа байдаг. Нэгдүгээрт, усан санг гараар эхлүүлэх шаардлагагүй, ажил бэлэн болмогцоо гүйцэтгэж эхэлдэг. Хоёрдугаарт, бид илгээхусан сан руу хийх даалгавар, биш тэдгээрийг овоолон дээр тавь. Нэмж дурдахад, Pool анги нь Threaded-аас өвлөгддөггүй тул бусад урсгал руу (Ажилчин-аас ялгаатай) дамжуулах боломжгүй.

Ажилчид болон усан сангууд даалгавраа хийж дуусмагц цэвэрлэж, өөрсдөө гараар дуусгах нь сайн туршлага юм. Thread класс ашиглан үүсгэсэн Threadууд нь мөн эх thread-д хавсаргасан байх ёстой.

pthreads ба (im)mutability

Бидний ярих сүүлийн анги бол pthreads v3-ийн шинэ нэмэлт болох Volatile юм. Үл хувирах чадвар нь 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->) өгөгдөл); // 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 ангиас тогтоосон өөрчлөгдөшгүй байдлыг дарж байгааг харж болно.

Хувьсах чадвар ба дэгдэмхий анги болох массивуудын сэдвийг хамрах өөр нэг сэдэв бий. Pthread-д Threaded классын шинж чанарт массивууд хуваарилагдах үед автоматаар дэгдэмхий объектууд руу шилждэг. Учир нь олон PHP контекстийн массивыг удирдах нь зүгээр л аюулгүй биш юм.

Зарим зүйлийг илүү сайн ойлгохын тулд жишээг дахин харцгаая.

$ массив =; $даалгавар = шинэ анги($массив) Thread-ыг сунгана (хувийн $өгөгдөл; нийтийн функц __construct(массив $массив) ( $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) */

Дэд бүлэг() оператор (дээр үзүүлсэн шиг) массивын үйлдлийг дэмждэг учраас Дэгдэмхий объектуудыг массив мэтээр авч үзэж болно гэдгийг бид харж байна. Гэсэн хэдий ч, дэгдэмхий ангиуд нь array_pop, array_shift гэх мэт үндсэн массив функцийг дэмждэггүй. Үүний оронд Threaded анги нь бидэнд суулгасан аргууд гэх мэт үйлдлүүдийг өгдөг.

Жагсаал болгон:

$өгөгдөл = шинэ анги өргөтгөл тогтворгүй ( нийтийн $a = 1; нийтийн $b = 2; нийтийн $c = 3; ); var_dump($ өгөгдөл); var_dump($дата->поп()); var_dump($data->shift()); var_dump($ өгөгдөл); /* Гаралт: object(class@nonymous)#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 = new class extensions Thread ( public $i = 0; public function run() ( for ($i = 0; $i i; ) ) ); $counter->start(); for ($i = 0; $i i; ) $counter->join(); var_dump($counter->i); // 10-аас 20 хүртэлх тоог хэвлэнэ

Синхрончлолыг ашиглахгүйгээр гаралт нь тодорхойлогч биш юм. Олон урсгалууд нь хяналтгүй хандалтгүйгээр нэг хувьсагч руу бичдэг бөгөөд энэ нь шинэчлэлтүүд устах болно гэсэн үг юм.

Хугацаа нэмснээр 20-ийн зөв гаралтыг авахын тулд үүнийг засъя:

$counter = new class extensions Thread ( public $i = 0; public function run() ( $this->синхрончлогдсон(функц () ( for ($i = 0; $i i; ) ); ) ); $counter->start(); $counter->синхрончлогдсон(функц ($тоолуур) ( for ($i = 0; $i i; ) ), $counter); $counter->нэгдэх(); 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->синхрончлогдсон(функц ($counter) ( if ($counter->cond !== 2) ( $counter->wait(); // нөгөө нь эхэлж эхлэхийг хүлээнэ үү ) ($i = 10; $i notify(); if ($counter->cond === 2) ( $counter->cond = 1; $counter->wait(); ) ) ), $counter); $counter->нэгдэх(); /* Гаралт: 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 хэрхэн ашиглагдаж болохыг судалж эхлэх боломжтой! Энэ бол бидний дараагийн нийтлэлийн сэдэв байх болно.

Хэрэв та дараагийн бичлэгийн орчуулгыг сонирхож байгаа бол надад мэдэгдээрэй: нийгмийн сүлжээн дэх сэтгэгдэл. сүлжээнд саналаа өгч, нийтлэлийг хамтран ажиллагсад, найзуудтайгаа хуваалцаарай.


02.10.2011, 21:27

Нэг залууг зодож, цамцыг нь модонд өлгөснийхээ төлөө.Тэгээд тэр тэнэг залууг ганцаараа хэдэн км хөөгөөд унасан хойно нь шээж эхэлсэн.Гэхдээ тэд үүнийг хүртэх ёстой байсан.

Том компанид би нэг охиныг доромжилж, найз залуу нь түүнийг хямдралаар худалдаж авсан, мөн микроавтобусанд хүн бүрийн өвөр дээр банана идэж, хальс тавилаа гэж хэлсэн, би бас бааранд лесбиян шоунуудыг байнга зохион байгуулдаг. VIP клубын үйлчлэгч нарын тухай ярьж, тайлбар өгсөн ч би ер нь согтуу байсан, чи сэрээд ичиж байгаа бол хүмүүст хайртай гэдгээ шууд мартдаг, гэхдээ яг яагаад миний тухай байсныг санахгүй байна.

Сүүлчийн согтуугийн дараа би залхаж байна:
1. тагтнаас нөгөө залуу руу "намайг сороорой" гэж хашгирав
2. тамхи идсэн
3. алим шидсэн
4. тэр залуу руу залгаад би түүнд бүдүүлэг секс хийхгүй гэж хэлсэн
5. усан үзмийн шүүсэнд живсэн бух
6. ээж рүүгээ залгаад намайг ухаантай гэж хэлсэн
7. Би найзынхаа найз залуугаас дарс авчирч өгөхийг хүссэн.
8. Би жорлонгийн хажуугаар шээсэн, учир нь тэд 2 байсан - Би буруу сонгосон, тэгээд унасан.
9. ваннаас унасан

Би хоёр шил шампан дарс уусан ч нөхрийнхөө араас нэг удаа хутга барин гүйж байсан. Маргааш өглөө нь би айж эхлэв - хэрэв би түүнийг хутгаар цохивол яах вэ, гэхдээ би зүгээр л түүнийг айлгах гэж шийдсэн. Би яагаад ийм цохилт авснаа мэдэхгүй байна!

Би согтуурахаараа цэцэрлэгт хүрээлэнд очиж шоглох гэж онигоо хайдаг, эсвэл форум дээр ийм сэдвүүдийг үүсгэдэг гэх мэт үргэлж ижил зүйл байдаг ... өглөө би тэнэг юм болов уу?

Нэгэн удаа нэг залуу намайг цохиход би маш их согтуу байсан тул түүнд юу ч болохгүй гэж олон нийтэд тайлбарлаж эхэлсэн, учир нь би "Цуст Мэри" (тэд байсан) байсан бөгөөд энэ хоч миний сэтгэлд маш их шингэсэн тул би бараг л "Би Цуст Мэри байна" гэж уулзсан бүх хүмүүст хашгирав, аз болоход энэ нь миний төрсөн хотод байгаагүй.

-* хуучин залуу руугаа утасдаж, түүний тухай бодож байсан бүхнээ илэрхийлэв
*хайрт руугаа залгаад би түүнийг ямар их хүсч байгаагаа хэлэв
*тугалган цаастай шаурма идсэн
* клубт тааралдсан залуу надад тусалж, ус авчирсан ч гэсэн хараал идсэн
* тэмцээнд клубт стриптиз бүжиглэж, хоёрдугаар байр эзэлсэн
*танихгүй хүн рүү мөс шидэв
*Манай хүний ​​найз шар Хаммер унадаг. Би Солонгост ийм юм харж байгаагүй. Бид бүгд хамтдаа үдэшлэгт явах үед. Би хүнийхээ машинаас тонгойн урд явж байсан Хаммер руу заан энэ машиныг миний найз гэж хашгирав.
*өчигдөр би клубт байсан. Би өглөө такси бариад гэртээ харихдаа жолоочид: [Солонгос хэлнээс орчуулга. үгчлэн!] "Миний идсэн хоол надад гарч ирэхийг хүсч байна гэж хэлсэн!"
*Би бас монгол найзтай. Би нуруун дээр нь гараад намайг нуруун дээрээ үүрч, миний монгол морь гэж гудамж даяар хашгирав.
гэхдээ ерөнхийдөө илүү их зүйл байсан, та санахгүй байх болно ...

Би тэр залуу руу өглөөний 4 цагт "Сайн амраарай, хонгор минь" гэж бичсэн.

Найзууд бид хоёр коньяк ууж согтсон, бүгд гэртээ харьж, би тэнэг юм шиг такси дуудаж (шөнийн 3 цаг байсан) 4 сарын өмнө салсан (бид найзууд хэвээр үлдсэн) хуучин найз залуутайгаа уулзахаар очив. Би яаж орцонд нь орж ирээд байр руу нь орж ирээд хаалгыг нь эвдэн "МАРАТ НАДТАЙ ГЭРЛЭЭЧ" гэж хашгирч байснаа санаж байна уу, хөөрхий тэр галзуурч намайг гэртээ чирэн хүйтэн шүршүүрт оруулаад хатуу цай өгөв. 2 цагийн дараа би гараад юу хийснээ ойлгоод ҮНЭХЭЭР ИЧЭЭДЭЭ.Үүний дараа бид 2 эвлэрсэн одоо хүртэл хамт байгаа. Үүний дараа би дахиад нэг шил шампан дарс уудаггүй.


...

02.10.2011, 22:09

Амиа алдсан эмэгтэй нэг залуутай хамт цэцэрлэгт хүрээлэнгээр алхаж яваад хажууд минь биш хэдэн алхам түрүүлж алхаж байгаад намайг гомдоосон юм шиг санагдав. Би гомдоод модонд авирсан ч тэр анзаарсангүй... тэр цэцэрлэгийн эргэн тойронд цаг хагасын турш намайг хайж гүйж ... би мод дээр тайвширч, өглөө болтол унтлаа. ...
...
Гэхдээ өглөө нь би яаж мөчир дээр ирснээ шууд санахгүй байв. Хөөрхий, дараа нь яаж байсан юм бэ
;D;D;D

Тайлбар

02.10.2011, 22:42

Ухаантай байхдаа хийсэн зарим үйлдлээсээ ичиж байна :) Гэхдээ энэ нь философид илүү ойр байдаг. Согтуу байхдаа... зөндөө юм хөгжилтэй, ичмээр... үгүй ​​ээ уучлаарай))))

Елена Лотус

02.10.2011, 23:17

Өчигдөр би утсаа (ООО!!!) минийх биш болсныг мэдээд маш их согтсон. Тэгээд (хэн намайг хулгана шиг уудаг гэж битгий хэлээрэй) тэгээд нэг юм хийсэн... тэр зөвхөн ойр дотны найзууддаа, том нууцаар, тэгээд би хэнд хэлэхээ бодно... Паберти ресторан ахин цочирдов.Одоо би юу болсныг харна гэж найдан зургийн цомог үзэж байна: (гэхдээ би ичихгүй ээ... үгүй... би зүгээр л өөрийгөө олигтой гэж бодсон.

02.10.2011, 23:31

;D;D;D
Нагац эгч нар архи ууж болохгүй гэж би үргэлж баримталж ирсэн!!! БҮГД!!!;)

..;D;D;D та үнэнийг хэлж байна

02.10.2011, 23:36

Согтуу эмэгтэй бол хятадын хүрэмтэй адил: зөөлөн бөгөөд тохиромжтой.
Галыгин

Елена Лотус

02.10.2011, 23:41

Гэхдээ эрчүүд тийм дуртай юу?Хүн бүр ууж болно. бас нагац эгч нараа... болгоомжтой байгаарай... өнөөдөр толгой чинь өвдөөгүй... сэтгэл чинь өвдөөд байна... уух уу? Энэ бол зүгээр л харгис тойрог;)

03.10.2011, 00:15

Залуу, эрүүл байхдаа юу ч юм уу, юу ч юм уу :)

03.10.2011, 01:48

эмэгтэйчүүдийн форумаас сонгон хулгайлсан :)

Би ээжийнхээ өмнө угаалгын сагсанд шээх шахсан..... жорлонтой андуурч.... өө....

Амиа алдсан эмэгтэй нэг залуутай хамт цэцэрлэгт хүрээлэнгээр алхаж яваад хажууд минь биш хэдэн алхам түрүүлж алхаж байгаад намайг гомдоосон юм шиг санагдав. Би гомдоод модонд авирсан ч тэр анзаарсангүй... тэр цэцэрлэгийн эргэн тойронд цаг хагасын турш намайг хайж гүйж ... би мод дээр тайвширч, өглөө болтол унтлаа. ...
...
Гэхдээ өглөө нь би яаж мөчир дээр ирснээ шууд санахгүй байв. Хөөрхий, дараа нь яаж байсан юм бэ

Тагтан дээр ээжийн сонгино тарьдаг сав, савнууд байсан.Би энэ сав болгонд "сул" иддэг байсан =(((((Мэдээж би ээждээ хэлэхгүй, бүгдийг нь шидчих)) хогийн сав, би энд байна би чиний ногоонууд дээр шээхээр шийдсэн! За, энэ нь үргэлжлэн ургаж, дараа нь салат руу оров.

03.10.2011, 05:35

Найзууд бид хоёр коньяк ууж согтсон, бүгд гэртээ харьж, би тэнэг юм шиг такси дуудаж (шөнийн 3 цаг байсан) 4 сарын өмнө салсан (бид найзууд хэвээр үлдсэн) хуучин найз залуутайгаа уулзахаар очив. Би яаж орцонд нь орж ирээд байр руу нь орж ирээд хаалгыг нь эвдэн "МАРАТ НАДТАЙ ГЭРЛЭЭЧ" гэж хашгирч байснаа санаж байна уу, хөөрхий тэр галзуурч намайг гэртээ чирэн хүйтэн шүршүүрт оруулаад хатуу цай өгөв. 2 цагийн дараа би гараад юу хийснээ ойлгоод ҮНЭХЭЭР ИЧЭЭДЭЭ.Үүний дараа бид 2 эвлэрсэн одоо хүртэл хамт байгаа. Үүний дараа би дахиад нэг шил шампан дарс уудаггүй.

Энэ бол үнэхээр жинхэнэ хайрын түүх юм.
Мөн архины ашиг тусын талаар.

(Уух уу, охидоо, аз жаргал чамд ирэх болно.)

PHP дээр олон урсгалыг дуурайх хэд хэдэн шийдлүүд вэб дээр хөвж байна. Ихэнхдээ тэдгээр нь сэрээ дээр суурилдаг боловч ашиглах сэдвийн хувьд өөр өөр байдаг буржгар, proc_openгэх мэт.

Надад тохиолдсон бүх сонголтууд нэг шалтгааны улмаас надад тохирохгүй байсан тул би өөрийнхөө шийдлийг бичих шаардлагатай болсон. Би дараах шаардлагуудыг тавьсан.

  • сэрээ ашиглах;
  • Шаардлагатай өргөтгөлүүд байхгүй тохиолдолд интерфейсийг хадгалах синхрон горим;
  • Хүүхдийн процессыг дахин ашиглах;
  • Процессуудын хооронд бүрэн мэдээлэл солилцох. Тэдгээр. аргументуудтай гүйж, дууссаны дараа үр дүнг авах;
  • Үйл ажиллагааны явцад хүүхдийн "утас" үйл явц ба үндсэн үйл явцын хооронд үйл явдлуудыг солилцох чадвар;
  • Дахин ашиглах, аргумент дамжуулах, үр дүнд хүрэхийн зэрэгцээ урсгалын сантай ажиллах;
  • Ажиллах үеийн алдааг зохицуулах;
  • Ажлыг гүйцэтгэх хугацаа, утсаар ажиллахыг хүлээх, эхлүүлэх;
  • Хамгийн их гүйцэтгэл.

Үүний үр дүнд AzaThread номын сан (хуучнаар CThread) гарч ирэв.

Тодорхойлолт

AzaThread нь thread анги үүсгэх энгийн интерфейсээр хангадаг. Энэ нь үнэндээ асинхрон ажиллахын тулд тусдаа процессуудыг ашигладаг, гэхдээ та үүнд санаа зовох хэрэггүй. Та thread-ээс үйл явдлуудыг илгээх, үр дүнг буцаах, нэг хэлхээг олон удаа ашиглах, эхлүүлэх аргументуудыг дамжуулах, эсвэл ажил явагдаж байгааг анхаарч үзэхгүйгээр халуун бялуу гэх мэт 16 урсгалын сан үүсгэж болно. янз бүрийн процесст.

Нэмж дурдахад, та өөр өөр горимд номын сангийн гүйцэтгэлийг хялбархан шалгах боломжтой.

Бүрэн ажиллахын тулд дараах өргөтгөлүүд шаардлагатай: чөлөөтэй, posixТэгээд pcntl.

Номын сан нь LibEvent болон хосолсон залгууруудыг процессуудын хооронд харилцахад ашигладаг. Өгөгдөл дамжуулах 5 сонголтыг дэмждэг (аргумент, үр дүн, үйл явдлын өгөгдөл)!

Би гүйцэтгэлийн өгөгдлийн хамт сонголтуудыг нэн даруй танилцуулж байна. Intel Core i7 2600K 3.40 Ghz (VMware виртуал машин дээрх Ubuntu 11.04) дээр найман хэлхээний сантай туршсан. Туршилтын 10 давталтын дундаж үр дүнг jps хэлбэрээр өгсөн (секундэд хийх ажил - зүгээр л аргумент хүлээн авах, секундэд өгөгдөл илгээх ажлын тоо).

Сокетуудтай ажиллах өргөтгөлийг автоматаар сонгоно. Хэрэв боломжтой бол өргөтгөлийг ашиглана залгуурууд, энэ нь сайжруулсан гүйцэтгэлийг өгдөг. Үгүй бол үүнийг ашиглах болно урсгал.

Хүүхдийн процесс нь боломжтой бүх дохиог сонсдог. Анхдагч байдлаар, бүгдийг нь (SIGWINCH болон SIGINFO-оос бусад) дараа нь унтраадаг. Гэхдээ дохионы нэр бүхий thread ангид аргыг үүсгэснээр үүнийг хялбархан дарж болно. Жишээ нь sigWinch.

Эцэг эхийн процесст бүх дохиог мөн анхдагч байдлаар саатуулдаг. ListeMasterSignals ангийн параметрийг false гэж тохируулснаар үүнийг өөрчилж болно. Энэ тохиолдолд зөвхөн SIGCHLD боловсруулагдана. Та m нэртэй статик аргыг үүсгэснээр өөрийн зохицуулагчийг хялбархан нэмж болно<имя сигнала>. Жишээлбэл, mSigTerm.

Хүүхдийн процесс ямар нэгэн шалтгаанаар нас барвал шинэ даалгавар эхлэхэд анги автоматаар салаа болно. Энэ нь анзааралгүй тохиолддог бөгөөд та энэ талаар огт бодох шаардлагагүй болно. Аливаа алдаа гарсан тохиолдолд жишээг дахин үүсгэх шаардлагагүй.

Хүүхдийн процесс нь эцэг эхийн үйл явц байгаа эсэхийг үе үе шалгадаг. Хэрэв гэнэт үхвэл хүүхэд автоматаар дуусна.

Устгагчийг дуудах үед урсгал эсвэл урсгалын санд ашигладаг бүх нөөц автоматаар цэвэрлэгддэг. Гэхдээ тэдгээрийг цэвэрлэх аргыг дуудаж хүчээр цэвэрлэж болно. Энэ тохиолдолд утас/сөөрмийг цаашид ашиглах боломжгүй.

Стандарт тохиргоотой бол анги үүсгэсэн даруйд урсгалыг урьдчилан эхлүүлдэг. Хэрэв та prefork параметрийг худал гэж тохируулсан бол салаа нь зөвхөн ажил эхлэх үед л гарч ирнэ.

Ерөнхийдөө маш олон тохируулж болох параметрүүд байдаг. Сэрээний дараа хүүхдийн процессын нэрийг өөрчлөх (баруулагчийн pName параметр), даалгаврын гүйцэтгэлийн хугацааны завсарлага (timeoutWork), хүүхдийн процессын даалгаврыг хүлээх хамгийн их хугацааны завсарлага (timeoutMaxWait), өмнөх процессын завсарлага. эхлүүлэх хугацаа (timeoutInit), залгууруудыг унших буферийн хэмжээ (pipeReadSize , pipeMasterReadSize). Та хэлхээний олон үйлдэл хийх горимыг идэвхгүй болгож болно (олон даалгавар). Энэ тохиолдолд даалгавраа дуусгах бүрт хүүхдийн процесс үхэж, дараагийн хөөргөлтөд дахин салаа болно. Энэ нь гүйцэтгэлийг мэдэгдэхүйц бууруулах болно.

Код нь туршилтаар бүрхэгдсэн бөгөөд дэлгэрэнгүй баримтжуулсан бөгөөд ашиглалтын жишээг example.php файлаас харж, ажиллуулж болно. Алдаатай ажиллах илүү төвөгтэй жишээг нэгжийн тестийн кодоос харж болно.

Дибаг хийх горим байдаг бөгөөд энэ нь яг юу болж байгаа, хаана байгаа талаар маш дэлгэрэнгүй мэдээллийг харуулдаг.

Хэрэглэх жишээ

Гол онцлог нь дээд зэргийн энгийн байдал юм. Хэрэв та ямар нэг зүйлийг тусдаа "thread"-д ажиллуулахыг хүсвэл дараах код хангалттай.

Class ExampleThread Thread өргөтгөл (хамгаалагдсан функц процесс() ( // Зарим нь энд ажилладаг ) ) $thread = new ExampleThread(); $thread->wait()->run();

Хэрэв бүрэн хэмжээний ажилд шаардлагатай бүх зүйл байгаа бол даалгаврыг асинхроноор гүйцэтгэнэ. Үгүй бол бүх зүйл ажиллах болно, гэхдээ синхрон горимд.

Параметрийг дамжуулж үр дүнг гаргаснаар код нь арай илүү төвөгтэй харагдах болно:

Class ExampleThread Thread-ыг өргөтгөдөг (хамгаалагдсан функц процесс() ( $this->getParam(0); буцаана ) ) $thread = new ExampleThread(); $thread->wait()->run(123); $үр дүн = $thread->хүлээх()->getResult();

Үүний нэгэн адил, гараараа бага зэрэг долгионоор бид урсгалаас үйл явдлын боловсруулалтыг нэмнэ:

Class ExampleThread Thread өргөтгөдөг ( const EV_PROCESS = "process"; хамгаалагдсан функц процесс() ( $events = $this->getParam(0); for ($i = 0; $i trigger(self::EV_PROCESS, $event_data); ) ) ) // Нэмэлт аргумент. $additionalArgument = 123; $thread->bind(ExampleThread::EV_PROCESS, функц ($үйл явдлын_нэр, $үйл явдлын_өгөгдөл, $нэмэлт_арг) ( // үйл явдлын боловсруулалт), $additionalArgument); $үйл явдал = 10; // thread үүсгэх үйл явдлын тоо // Эхний дуудлагын өмнө хэлхээг гараар хүлээхээс зайлсхийхийн тулд // та preforkWait шинж чанарыг удамшлын ангид TRUE болгож дарж болно $thread->wait(); $thread = шинэ ExampleThread(); $thread->run($events)->хүлээх();

Эцэст нь, ажлын үеийн алдаатай ажиллах найман урсгалын санг ашиглан:

$threads = 8 // Threads-ийн тоо $pool = new ThreadPool("ExampleThread", $threads); $ тоо = 25; // Даалгаврын тоо $left = $num; // Үлдсэн даалгаврын тоо ( // Хэрэв санд чөлөөт хэлхээ байгаа бол // Бидэнд ($pool->hasWaiting() && $left > 0) гүйцэтгэх ажлууд байсаар байна ( // Эхлэх үед бид дараахийг авна. урсгалын id $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) ( foreach ($threadId => $result) ( / / Амжилттай гүйцэтгэсэн даалгавар // Үр дүнг урсгалын дугаараар тодорхойлж болно // ($threadId) $num--; ) ) if ($failed) ( // Гүйцэтгэлийн алдааг зохицуулах. // Ажлыг амжилтгүй гүйцэтгэсэн гэж үзнэ. // хэрэв хүүхэд процесс гүйцэтгэх явцад үхсэн эсвэл // даалгавар гүйцэтгэх хугацаа дууссан бол foreach ($threadId байдлаар бүтэлгүйтсэн) ( $left++; ) ) ) while ($num > 0); // Бүх хүүхдийн процессыг зогсооно. Бид усан сангийн ашиглаж байгаа нөөцийг цэвэрлэдэг. $pool->цэвэрлэх();

Гүйцэтгэлийн шалгалтын үр дүн

Би Ubuntu 11.04-тэй хоёр машин дээр туршилт хийсэн.
Эхнийх нь Intel Core i3 540 3.07 Ghz.
Хоёр дахь нь Intel Core i7 2600K 3.40 Ghz (Ubuntu нь VMware виртуал машин дээр ажилладаг).

Та бүтээмжийн өсөлтийг үнэлэхийн тулд би үр дүнг энгийнээр танилцуулж байна. Дахин хэлэхэд эдгээр нь jps (секундэд хийх ажил - секундэд хийх ажлын тоо) дахь тестийн 10 давталтын дундаж үр дүн юм.

Даалгаврын хувьд threads нь дараах хогийг гүйцэтгэдэг.

Учир нь ($i = 0; $i

Эхний үр дүнг синхрон ажиллагааны горимд (салаагүй) зааж өгсөн болно. Би эхний тохиргоонд 18 ба 20 утсыг туршиж үзээгүй, учир нь 12-ны дараа гүйцэтгэл буурч эхэлсэн.

Утаснуудын тоо Эхний тохиргоо Хоёрдугаарт
0 553 763
1 330 669
2 580 1254
4 1015 2188
8 1040 2618
10 1027 2719
12 970 2739
16 958 2904
18 - 2830
20 - 2730

Өөрөөр хэлбэл, гүйцэтгэл нь процессороос хамааран 2-4 дахин эсвэл түүнээс дээш нэмэгддэг!

Шаардлагатай параметр бүхий хэд хэдэн тестийг ажиллуулдаг код жишээнүүд/speed_test.php файлд байна. Тиймээс та гүйцэтгэлийг хялбархан шалгаж, өөртөө тохирох утаснуудын тоог сонгох боломжтой.

Номын сан нь хэн нэгэнд хэрэгтэй бол би маш их баяртай байх болно. Аливаа функцийн хүсэлт эсвэл илрүүлсэн алдааг Github дээр үлдээж болно, би номын санг яаралтай засч сайжруулна.

PHP дээр олон урсгалыг дуурайх хэд хэдэн шийдлүүд вэб дээр хөвж байна. Ихэнх тохиолдолд тэдгээр нь сэрээ дээр суурилдаг боловч curl, proc_open гэх мэт сэдвүүдийн хувилбарууд байдаг.

Ямар нэг шалтгааны улмаас надад тааралдсан бүх сонголтууд надад тохирохгүй байсан тул би өөрийнхөө шийдлийг бичих шаардлагатай болсон.
Би дараах шаардлагуудыг тавьсан.

  • сэрээ ашиглах;
  • Шаардлагатай өргөтгөлүүд байхгүй тохиолдолд интерфейсийг хадгалах синхрон горим;
  • Хүүхдийн процессыг дахин ашиглах;
  • Процессуудын хооронд бүрэн мэдээлэл солилцох. Тэдгээр. аргументуудтай гүйж, дууссаны дараа үр дүнг авах;
  • Үйл ажиллагааны явцад хүүхдийн "утас" үйл явц ба үндсэн үйл явцын хооронд үйл явдлуудыг солилцох чадвар;
  • Дахин ашиглах, аргумент дамжуулах, үр дүнд хүрэхийн зэрэгцээ урсгалын сантай ажиллах;
  • Ажиллах үеийн алдааг зохицуулах;
  • Ажлыг гүйцэтгэх хугацаа, утсаар ажиллахыг хүлээх, эхлүүлэх;
  • Хамгийн их гүйцэтгэл;
Үр дүн нь номын сан юм AzaThread(хуучин нэр - CThread).

Тэвчээргүй хүмүүст эх сурвалжийн холбоосыг эндээс авна уу.
github.com/Anizoptera/AzaThread

Тодорхойлолт

AzaThread нь thread анги үүсгэх энгийн интерфейсээр хангадаг. Энэ нь үнэндээ асинхрон ажиллахын тулд тусдаа процессуудыг ашигладаг, гэхдээ та үүнд санаа зовох хэрэггүй. Та thread-ээс үйл явдлуудыг илгээж, үр дүнг буцаах, нэг утсыг олон удаа ашиглах, түүн рүү эхлүүлэх аргументуудыг дамжуулах, эсвэл ажил янз бүрийн процессоор явагдаж байгааг анхаарч үзэхгүйгээр халуун бялуу шиг даалгавраа хүрз болгон 16 утастай сан үүсгэж болно. .

Нэмж дурдахад, та өөр өөр горимд номын сангийн гүйцэтгэлийг хялбархан шалгах боломжтой.

Бүрэн ажиллахын тулд дараах өргөтгөлүүд шаардлагатай: чөлөөтэй, posixТэгээд pcntl.

Номын сан нь LibEvent болон хосолсон залгууруудыг процессуудын хооронд харилцахад ашигладаг. Өгөгдөл дамжуулах 5 сонголтыг дэмждэг (аргумент, үр дүн, үйл явдлын өгөгдөл)!

Би гүйцэтгэлийн өгөгдлийн хамт сонголтуудыг нэн даруй танилцуулж байна. Intel Core i7 2600K 3.40 Ghz (VMware виртуал машин дээрх Ubuntu 11.04) дээр найман хэлхээний сантай туршсан. Туршилтын 10 давталтын дундаж үр дүнг jps хэлбэрээр өгсөн (секундэд хийх ажил - зүгээр л аргумент хүлээн авах, секундэд өгөгдөл илгээх ажлын тоо).

Сокетуудтай ажиллах өргөтгөлийг автоматаар сонгоно. Хэрэв боломжтой бол өргөтгөлийг ашиглана залгуурууд, энэ нь сайжруулсан гүйцэтгэлийг өгдөг. Үгүй бол үүнийг ашиглах болно урсгал.

Хүүхдийн процесс нь боломжтой бүх дохиог сонсдог. Анхдагч байдлаар, бүгдийг нь (SIGWINCH болон SIGINFO-оос бусад) дараа нь унтраадаг. Гэхдээ дохионы нэр бүхий thread ангид аргыг үүсгэснээр үүнийг хялбархан дарж болно. Жишээлбэл sigWinch.

Эцэг эхийн процесст бүх дохиог мөн анхдагч байдлаар саатуулдаг. Үүнийг ангийн параметрийг тохируулах замаар өөрчилж болно Мастер дохиог сонсхудал. Энэ тохиолдолд зөвхөн SIGCHLD боловсруулагдана. Та нэртэй статик аргыг үүсгэснээр өөрийн зохицуулагчдыг хялбархан нэмж болно м< имя сигнала > . Жишээлбэл mSigTerm.

Хэрэв хүүхдийн процесс ямар нэг шалтгаанаар үхвэл шинэ даалгавар эхлэхэд анги автоматаар салаа болно. Энэ нь анзааралгүй тохиолддог бөгөөд та энэ талаар огт бодох шаардлагагүй болно. Аливаа алдаа гарсан тохиолдолд жишээг дахин үүсгэх шаардлагагүй.

Хүүхдийн процесс нь эцэг эхийн үйл явц байгаа эсэхийг үе үе шалгадаг. Хэрэв гэнэт үхвэл хүүхэд автоматаар дуусна.

Устгагчийг дуудах үед урсгал эсвэл урсгалын санд ашигладаг бүх нөөц автоматаар цэвэрлэгддэг. Гэхдээ тэд аргыг дуудаж хүчээр цэвэрлэж болно цэвэрлэх. Энэ тохиолдолд утас/сөөрмийг цаашид ашиглах боломжгүй.

Стандарт тохиргоотой бол анги үүсгэсэн даруйд урсгалыг урьдчилан эхлүүлдэг. Хэрэв та параметрийг тохируулсан бол урьдчилан сэрээ false, дараа нь сэрээ нь зөвхөн ажил эхлэх үед л гарч ирнэ.

Ерөнхийдөө маш олон тохируулж болох параметрүүд байдаг. Сэрээний дараа хүүхдийн үйл явцын нэрийг өөрчлөх (параметр pNameбүтээгч), даалгаврын үргэлжлэх хугацаа ( ажлын хугацаа хэтэрсэн), хүүхдийн процесс даалгавраа хүлээх хамгийн их хугацааны завсарлага ( timeoutMaxWait), урьдчилан эхлүүлэх хугацаа ( timeoutInit), сокет унших буферийн хэмжээ ( pipeReadSize, pipeMasterReadSize).
Та хэлхээний олон үйлдэл хийх горимыг идэвхгүй болгож болно ( олон ажил). Энэ тохиолдолд даалгавраа дуусгах бүрт хүүхдийн процесс үхэж, дараагийн хөөргөлтөд дахин салаа болно. Энэ нь гүйцэтгэлийг мэдэгдэхүйц бууруулах болно.

Кодыг туршилтаар бүрхэж, нарийвчлан баримтжуулсан бөгөөд ашиглах жишээг файлаас харж, ажиллуулж болно жишээ.php.
Алдаатай ажиллах илүү төвөгтэй жишээг нэгжийн тестийн кодоос харж болно.

Яг юу болж байгаа, хаана байгаа талаар маш нарийн мэдээллийг харуулдаг дибаг хийх горим байдаг.

Хэрэглэх жишээ

Гол онцлог нь дээд зэргийн энгийн байдал юм. Хэрэв та ямар нэг зүйлийг тусдаа "thread"-д ажиллуулахыг хүсвэл дараах код хангалттай.
анги ExampleThread Thread өргөтгөдөг ( хамгаалагдсан функц процесс() ( // Зарим нь энд ажилладаг ) ) $thread = new ExampleThread(); $thread->wait()->run();
Хэрэв бүрэн хэмжээний ажилд шаардлагатай бүх зүйл байгаа бол даалгаврыг асинхроноор гүйцэтгэнэ. Үгүй бол бүх зүйл ажиллах болно, гэхдээ синхрон горимд.

Параметрийг дамжуулж, үр дүнг гаргаснаар код нь арай илүү төвөгтэй харагдах болно:
анги ExampleThread Thread өргөтгөдөг ( хамгаалагдсан функц процесс() ( $this->getParam(0); буцаана ) ) $thread = new ExampleThread(); $thread->wait()->run(123); $үр дүн = $thread->хүлээх()->getResult();

Үүний нэгэн адил, гараараа бага зэрэг долгионоор бид урсгалаас үйл явдлын боловсруулалтыг нэмнэ:
анги ExampleThread Thread өргөтгөдөг ( const EV_PROCESS = "процесс"; хамгаалагдсан функц процесс() ( $events = $this->getParam(0); for ($i = 0; $i)< $events; $i++) { $event_data = $i; $this->гох(self::EV_PROCESS, $үйл явдлын_өгөгдөл); ) ) ) // Нэмэлт аргумент. $additionalArgument = 123; $thread->bind(ExampleThread::EV_PROCESS, функц ($үйл явдлын_нэр, $үйл явдлын_өгөгдөл, $нэмэлт_арг) ( // үйл явдлын боловсруулалт), $additionalArgument); $үйл явдал = 10; // thread үүсгэх үйл явдлын тоо // Эхний дуудлагын өмнө хэлхээг гараар хүлээхээс зайлсхийхийн тулд // та preforkWait шинж чанарыг удамшлын ангид TRUE болгож дарж болно $thread->wait(); $thread = шинэ ExampleThread(); $thread->run($events)->хүлээх();

Эцэст нь, ажлын үеийн алдаатай ажиллах найман урсгалын санг ашиглан:
$threads = 8 // Threads-ийн тоо $pool = new ThreadPool("ExampleThread", $threads); $ тоо = 25; // Даалгаврын тоо $left = $num; // Үлдсэн даалгаврын тоо ( // Хэрэв санд чөлөөт хэлхээ байгаа бол // Бидэнд ($pool->hasWaiting() && $left > 0) гүйцэтгэх ажлууд байсаар байна ( // Эхлэх үед бид дараахийг авна. урсгалын id $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) ( foreach ($threadId => $result) ( / / Амжилттай гүйцэтгэсэн даалгавар // Үр дүнг урсгалын дугаараар тодорхойлж болно // ($threadId) $num--; ) ) if ($failed) ( // Гүйцэтгэлийн алдааг зохицуулах. // Ажлыг амжилтгүй гүйцэтгэсэн гэж үзнэ. // хэрэв хүүхэд процесс гүйцэтгэх явцад үхсэн эсвэл // даалгавар гүйцэтгэх хугацаа дууссан бол foreach ($threadId байдлаар бүтэлгүйтсэн) ( $left++; ) ) ) while ($num > 0); // Бүх хүүхдийн процессыг зогсооно. Бид усан сангийн ашиглаж байгаа нөөцийг цэвэрлэдэг. $pool->цэвэрлэх();

Гүйцэтгэлийн шалгалтын үр дүн

Би Ubuntu 11.04-тэй хоёр машин дээр туршилт хийсэн.
Эхнийх нь Intel Core i3 540 3.07 Ghz юм
Хоёр дахь нь Intel Core i7 2600K 3.40 Ghz (Ubuntu нь VMware виртуал машин дээр ажилладаг)

Та бүтээмжийн өсөлтийг үнэлэхийн тулд би үр дүнг энгийнээр танилцуулж байна.
Дахин хэлэхэд эдгээр нь jps (секундэд хийх ажил - секундэд хийх ажлын тоо) дахь 10 удаагийн туршилтын цувралын дундаж үр дүн юм.

Даалгаврын хувьд threads нь дараах хогийг гүйцэтгэдэг.
төлөө ($i = 0; $i< 1000; $i++) { $r = mt_rand(0, PHP_INT_MAX) * mt_rand(0, PHP_INT_MAX); }
Эхний үр дүнг синхрон ажиллагааны горимд (салаагүй) зааж өгсөн болно.
Би эхний тохиргоонд 18 ба 20 утсыг туршиж үзээгүй, учир нь 12-ны дараа гүйцэтгэл буурч эхэлсэн.

Утаснуудын тоо Эхний тохиргоо Хоёрдугаарт
0 553 763
1 330 669
2 580 1254
4 1015 2188
8 1040 2618
10 1027 2719
12 970 2739
16 958 2904
18 - 2830
20 - 2730

Өөрөөр хэлбэл, гүйцэтгэл нь процессороос хамааран 2-4 дахин эсвэл түүнээс дээш нэмэгддэг!

Шаардлагатай параметр бүхий хэд хэдэн тестийг ажиллуулдаг код нь файлд байна жишээнүүд/speed_test.php. Тиймээс та гүйцэтгэлийг хялбархан шалгаж, өөртөө тохирох утаснуудын тоог сонгох боломжтой.

найзууддаа хэл