ნასვამ მდგომარეობაში ჩადენილი რა ქმედებები გრცხვენიათ? პანიკური დარღვევების შესრულების ტესტის შედეგები

გულის ნევროზი (კარდიოფობია). ფობიის განსაკუთრებული ფორმა, პანიკის სინდრომთან ერთად, არის კარდიოფობია, რომელიც განსაკუთრებით დამახასიათებელი კლინიკური სურათისა და მნიშვნელოვანი სიხშირის გამო უნდა იყოს აღწერილი. ძირითადად გვხვდება ახალგაზრდებში, უფრო ხშირად მამაკაცებში და ასევე ბავშვებში.

პაროქსიზმული შფოთვის მდგომარეობა, რომელშიც პაციენტები შიშობენ, რომ გული შეწყვეტს მუშაობას და მოკვდება, შეიძლება მოხდეს სომატური დაავადების გარეშე. შემდეგი შეტევის დასაწყისში ჩნდება გულისრევა, თავბრუსხვევა, შინაგანი შფოთვა და გულის მცირე შეკუმშვა.

თუმცა, ხშირ შემთხვევაში, ყოველგვარი გაფრთხილების გარეშე, მძიმე შეტევა ხდება: პალპიტაციებიიგრძნობა მთელ სხეულში, გარკვეული მატება სისხლის წნევაგულის არეში შეკუმშვისა და შებოჭილობის მძიმე შეგრძნება, ჰაერის ნაკლებობა, ოფლიანობა, თავბრუსხვევა და დაღლილობის შეგრძნება (მაგრამ არა გონების დაკარგვა), კანკალი მთელ სხეულში და ძირითადი შიში. პაციენტს სჯერა, რომ გული წამში გაუჩერდება და მკვდარი ჩამოვარდება. ეს არის თვითგანადგურებისა და სიკვდილის შიში. ზე ძლიერი აღელვებაავადმყოფები გარბიან და დახმარებას ითხოვენ. თუ შიშის შეტევა ხდება მანქანით მგზავრობისას, პაციენტი იძულებულია გაჩერდეს და შეისვენოს.

პირველი შეტევის შემდეგ ხდება ფობიის განვითარება. პაციენტები კარგავენ ფსიქიკურ წონასწორობას, ცხოვრობენ მუდმივ შიშში, ელოდება მომდევნო შეტევას ან სიკვდილს, განიცდიან შიშის შიშს (მოლოდინის შიში, ფობია). ამავე დროს, მათ არ ეხმარება თერაპევტის შეტყობინება ნორმალური მაჩვენებლებიგულის ფუნქციონირება და არც დარწმუნება, რომ წინა შეტევებს არანაირი შედეგი არ მოჰყოლია. შეტევების სიხშირე და მათ შორის ინტერვალები არარეგულარულია. პერიოდულად, პაციენტი ყურადღებით აკვირდება თავის გულის ფუნქციებს, აკონტროლებს პულსს და აღრიცხავს მის უმნიშვნელო გადახრებს. ის შემთხვევით ექსტრასისტოლებს აღიქვამს, როგორც უიმედო შედეგის მქონე დაავადების უდავო ნიშნებს.

პაციენტები სიფრთხილით აკვირდებიან სხვა ვეგეტატიურ გამოვლინებებს, აგრეთვე მათ კეთილდღეობის უმნიშვნელო რყევებს. პაციენტები ზრუნავენ საკუთარ თავზე, ძლივს ბედავენ სიარულს, ცდილობენ თავიდან აიცილონ ყოველგვარი სტრესი, საზრუნავი და, პირველ რიგში, რთული სიტუაციები, რათა თავიდან აიცილონ თავდასხმა (ავარიული ქცევა). სიკვდილის შიშის ნაცვლად, ხშირ შემთხვევაში შიშისა და შიშის გამომწვევი სიტუაციების შიში სულ უფრო ჩნდება.

გარეგნობის პირობები. პირველი კარდიოფობიური შეტევის მიზეზი ხშირად არის მწვავე კონფლიქტი და გადატვირთვა, განცალკევება და იმედგაცრუება, მარტოობისა და მიტოვების სიტუაცია, ასევე შფოთვა ახლობლის გულის სიკვდილის შემთხვევაში.

იმის ცოდნა, რომ გულის სიკვდილი ყოველთვის შეიძლება მოხდეს, თუნდაც ახალგაზრდებში და ჯანმრთელებში, შემაშფოთებელი ფაქტორი ხდება. ყავისა და ნიკოტინის ინტენსიურმა მოხმარებამ შეიძლება გამოიწვიოს ეს პროცესი. დასაწყისი ხშირად ბავშვობიდან მოდის. ძირითადად განებივრებული და დამოკიდებული ბავშვები ზარალდებიან, გამოხატული დამოკიდებულებით დედაზე, მეტწილად ამბივალენტური დამოკიდებულებით: სიყვარულის მოლოდინი, ერთი მხრივ, დამოუკიდებლობის სურვილი აგრესიული იმპულსებით, მეორეს მხრივ, მიჯაჭვულობის წინააღმდეგობრივი ფანტაზიებით და. განშორება. ასეთი დამოკიდებულებები განსაკუთრებით საშიშია, როდესაც წყდება კავშირები, ხდება განშორება და იმედგაცრუება. კარდიოფობი ხშირად ცხოვრობს განშორების შიშით, სანამ მიხვდება, რომ ეს სურს და ეშინია. რეგულარულად ჩნდება მშობლებთან ერთობლივი პრობლემები და კონფლიქტები პარტნიორებთან.

მკურნალობა
თუ შიგნით მწვავე მდგომარეობაექიმის ყოფნა და მასთან საუბარი არ იწვევს გაუმჯობესებას, მითითებულია ტრანკვილიზატორები ან ბეტა-ბლოკატორები. შიშით დაავადებული ნევროზის მქონე სხვა პაციენტების მსგავსად, ბევრი ფობია ცდილობს თვითმკურნალობას ალკოჰოლით; მაგრამ მისი ეფექტი არასაკმარისია და ალკოჰოლზე დამოკიდებულების საშიშროება დიდია. ფარმაკოთერაპია არის მხოლოდ დამხმარე საშუალება, უპირველეს ყოვლისა მწვავე შემთხვევებში, ისევე როგორც პირველადი ეფექტური საშუალება.

ფსიქოთერაპია გადამწყვეტია. რაც მალე დაიწყება მით უკეთესი. მიზეზების შესწავლა და კონფლიქტური სიტუაციებიპირველი კარდიოფობიური შეტევებისთანავე შეიძლება შეაჩეროს შემდგომი ფობიის განვითარება. მოგვიანებით მკურნალობა უფრო რთულია და საჭიროა ხანგრძლივი ფსიქოთერაპია.

ამ და სხვა შფოთვითი აშლილობებისთვის განსაკუთრებით ნაჩვენებია ქცევითი თერაპია (აღგზნებად კონფრონტაცია, კოგნიტური თერაპია, თავდაჯერებულობის ტრენინგი). შფოთვის თავიდან აცილების ტრენინგის გამორჩეული თვისებაა ის, რომ ის მუშაობს დესენსიბილიზაციის მოდელზე (ყოველდღიური სიტუაციების შესაბამის პირობებში), ხოლო შფოთვის მართვის ტრენინგი იყენებს ფობიურ სიტუაციაში იძულებით ჩაძირვას (წყალდიდობას) და დაძლევის სტრატეგიების ფორმირებას. მძიმე შფოთვითი აშლილობის დროს აუცილებელია ჩატარდეს კლინიკური მკურნალობაფსიქოთერაპიის სხვადასხვა მოდელების გამოყენებით.


02.10.2011, 21:27

ბიჭის ცემისთვის და მაისურის ხეზე ჩამოკიდებისთვის.და იდიოტ ბიჭს მარტო დაედევნა ორიოდე კილომეტრი და როცა დაეცა დაიწყო ჭინჭრის ციება.მაგრამ დაიმსახურეს.

დიდ კომპანიაში, გოგოს შევაწუხე და ვუთხარი, რომ მისმა ბოიფრენდმა ის გაყიდვაში იყიდა და ასევე შეჭამა ბანანი და ყველას კალთაზე აყარა ქერქი მიკროავტობუსში, ასევე გამუდმებით ვაწყობ ლესბოსელებს ბარებში, ერთხელაც კალთების ქვეშ გავიხედე. მიმტანებს ვიპ კლუბში და აძლევდა კომენტარს, მაგრამ ზოგადად ცუდად ვარ ნასვამი, მაშინვე მავიწყდება, რომ მიყვარს ადამიანები, რომლებიც ამბობენ, გაიღვიძებ და გრცხვენია, მაგრამ არ გახსოვს, რატომ ზუსტად ჩემზე

ბოლო სიმთვრალის შემდეგ დავიღალე:
1. ყვიროდა აივნიდან ბიჭს "მომწოვე"
2. შეჭამა სიგარეტი
3. დაყარა ვაშლი
4. დაურეკა ბიჭს და უთხრა, რომ უხეში სექსს არ მივცემ
5. გრეიფრუტის წვენში დამხრჩვალი ხარები
6. დაურეკა დედაჩემს და მითხრა, რომ ფხიზელი ვიყავი
7. ჩემი მეგობრის ბოიფრენდს ვთხოვე, ღვინო მოგვიტანა.
8. ტუალეტს გავუწურე, რადგან 2 იყო - არასწორი ავირჩიე და მერე დავეცი
9. ამოვარდა აბანოდან

ერთხელ ქმრის უკან დანით შემოვვარდი ბინაში, თუმცა რამდენიმე ჭიქა შამპანური დავლიე. მეორე დილას შემეშინდა - დანით რომ დავარტყი, მაგრამ უბრალოდ მისი შეშინება გადავწყვიტე. და არ ვიცი რატომ მივიღე ასეთი დარტყმა!

ყოველთვის ერთი და იგივეა, როცა მთვრალი მივდივარ პარკში, რომ ვეძებ დაცინვას, ან ვქმნი ამ თემებს ფორუმზე... დილით ვფიქრობ, სულელი ვარ?...

ერთხელ ვიღაც ბიჭმა დამარტყა და ისე მთვრალი ვიყავი, რომ ხალხში დავიწყე ავუხსნა, რომ არაფერი გამომდიოდა, რადგან "სისხლიანი მარიამი" ვიყავი (ისინი) და ეს მეტსახელი ისე ჩამეძირა სულში, რომ თითქმის მე ვიყავი ვუყვირე ყველას, ვინც შევხვდი: "მე ვარ სისხლიანი მერი", საბედნიეროდ, ეს არ იყო ჩემს მშობლიურ ქალაქში

-* დაუძახა ჩემს ყოფილს, გამოვხატე ყველაფერი რაც მასზე ვფიქრობდი
*დამიძახა ჩემმა საყვარელმა, თქვა რამდენი მინდა
* მიირთვით შაურმა ფოლგით
* დაიფიცა ბიჭს, რომელიც კლუბში გავიცანი, თუმცა დამეხმარა და წყალი მომიტანა
*იცეკვა სტრიპტიზი კლუბში შეჯიბრში, მიიღო მეორე ადგილი
* ყინული ესროლა უცნობს
*ჩემი კაცის მეგობარი ყვითელ ჰამერს ატარებს. კორეაში მსგავსი არაფერი მინახავს. როცა ყველა ერთად წავედით წვეულებაზე. გადავედი ჩემი კაცის მანქანიდან და, მივუთითე ჰამერზე, რომელიც წინ მიდიოდა, დავიყვირე, რომ ეს მანქანა ჩემი მეგობარი იყო
*გუშინ ვიყავი კლუბში. დილით ტაქსით სახლში რომ მივდიოდი, მძღოლს ვუთხარი: [თარგმანი კორეულიდან. სიტყვასიტყვით!] "საჭმელი, რომელიც მე ვჭამე, მითხრა, რომ უნდა გამოვიდეს!"
*მე ასევე მყავს მონღოლი მეგობარი. მის ზურგზე ავდექი, ვაიძულე ზურგზე ამეყვანა და მთელ ქუჩაზე ვყვიროდი, რომ ის ჩემი მონღოლური ცხენი იყო.
მაგრამ ზოგადად კიდევ ბევრი იყო, არ გახსოვთ...

მე მივწერე ბიჭს დილის 4 საათზე " Ღამე მშვიდობისაძვირია"

მე და ჩემმა მეგობრებმა კონიაკით დავლიეთ, ყველა წავიდა სახლში, მე კი სულელურად გამოვიძახე ტაქსი (დილის 3 საათი იყო) და წავედი ჩემი ყოფილი ბიჭის სანახავად, რომელთანაც 4 თვის წინ დავშორდით (მეგობრები დავრჩით). არ გახსოვს, როგორ შევედი სადარბაზოში, მის ბინაში ჩავედი, მისი კარი ჩამტვრია და მეყვირა „მომთხოვე მარატ“, ის, საწყალი, გაგიჟდა, სახლში შემათრია, ცივ შხაპში, ძლიერი ჩაი მომცა. ორი საათის შემდეგ წამოვედი და როცა მივხვდი რაც გავაკეთე, მართლა შემრცხვა, ამის მერე შერიგდნენ და ახლაც ერთად არიან. ამის შემდეგ მე აღარ ვსვამ შამპანურს.


...

02.10.2011, 22:09

მოკლული ქალი ბიჭთან ერთად მიდიოდა ბაღში და მერე მომეჩვენა, რომ რაღაცნაირად შეურაცხყოფა მიაყენა ჩემამდე რამდენიმე ნაბიჯით წინ და არა ჩემს გვერდით. მეწყინა და ხეზე ავედი, მაგრამ ვერც კი შეამჩნია... საათნახევარი დარბოდა ბაღში და მეძებდა... მე კი მშვიდად გადავიდე ხეზე და დილამდე დავიძინე. ...
...
მაგრამ დილით მაშინვე ვერ ვიხსენებდი, როგორ მოვხვდი ტოტებზე. წმიდა სირცხვილი როგორ იყო შემდეგ
;დ;დ;დ

ინტერპრეტაცია

02.10.2011, 22:42

მე მრცხვენია ფხიზელ მდგომარეობაში ჩადენილი გარკვეული ქმედებების :) მაგრამ ეს უფრო ახლოსაა ფილოსოფიასთან. ლოთობისას... ბევრი რამ იყო სახალისო, სამარცხვინო... არა, ბოდიში)))))

ელენა ლოტუსი

02.10.2011, 23:17

გუშინ, როცა მივხვდი, რომ ჩემი ტელეფონი (ოოო!!!) ჩემი აღარ არის, დავლიე, მძიმედ და (ვინ მიცნობს, არ თქვა, რომ თაგვივით ვსვამ) მერე რაღაც გავაკეთე... მხოლოდ ახლო მეგობრებისთვის, ზოგადად საიდუმლო და მერე დავფიქრდები ვის ვუთხრა... რესტორანი პაბერტი ისევ შოკში ჩავარდა ახლა ფოტოგალერეას ვუყურებ იმ იმედით, რომ ვნახო რა მოხდა: (მაგრამ მე არ მრცხვენია... არა... უბრალოდ მეგონა, რომ წესიერი ვიყავი.

02.10.2011, 23:31

;დ;დ;დ
მე ყოველთვის ვამტკიცებდი, რომ დეიდებმა არ უნდა დალიონ!!! ყველა!!! ;)

..;დ;დ;დ სიმართლეს ამბობ

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 თვის წინ დავშორდით (მეგობრები დავრჩით). არ გახსოვს, როგორ შევედი სადარბაზოში, მის ბინაში ჩავედი, მისი კარი ჩამტვრია და მეყვირა „მომთხოვე მარატ“, ის, საწყალი, გაგიჟდა, სახლში შემათრია, ცივ შხაპში, ძლიერი ჩაი მომცა. ორი საათის შემდეგ წამოვედი და როცა მივხვდი რაც გავაკეთე, მართლა შემრცხვა, ამის მერე შერიგდნენ და ახლაც ერთად არიან. ამის შემდეგ მე აღარ ვსვამ შამპანურს.

ეს საკმაოდ რეალური ამბავისიყვარული.
და სასმელის სარგებლობის შესახებ.

(დალიეთ, გოგოებო, და ბედნიერება მოვა თქვენთან.)

არსებობს საკმაოდ ბევრი გადაწყვეტილებები, რომლებიც მცურავია ინტერნეტში PHP-ში მრავალნაკადის ემულაციისთვის. ყველაზე ხშირად ისინი ეფუძნება ჩანგლებს, მაგრამ ასევე არის ვარიაციები თემაზე curl, proc_open და ა.შ.

ამა თუ იმ მიზეზის გამო, ყველა ის ვარიანტი, რაც დამხვდა, არ მაწყობდა და ჩემი გადაწყვეტის დაწერა მომიწია.
მე მქონდა შემდეგი მოთხოვნები:

  • ჩანგლების გამოყენება;
  • სინქრონული რეჟიმი ინტერფეისის შენარჩუნებით საჭირო გაფართოებების არარსებობის შემთხვევაში;
  • ბავშვის პროცესების ხელახალი გამოყენება;
  • მონაცემთა სრული გაცვლა პროცესებს შორის. იმათ. გაუშვით არგუმენტებით და მიიღეთ შედეგი დასრულების შემდეგ;
  • მოვლენების გაცვლის შესაძლებლობა ბავშვის „ძაფის“ პროცესსა და ძირითად პროცესს შორის ოპერაციის დროს;
  • ძაფების აუზთან მუშაობა ხელახლა გამოყენების შენარჩუნებისას, არგუმენტების გაცემა და შედეგების მიღება;
  • მუშაობის დროის შეცდომების დამუშავება;
  • სამუშაოს შესრულების ვადები, ძაფით სამუშაოს მოლოდინი, ინიციალიზაცია;
  • მაქსიმალური შესრულება;
შედეგი არის ბიბლიოთეკა AzaThread(ძველი სახელი - CThread).

მოუთმენელთათვის აქ არის წყაროს ბმული:
github.com/Anizoptera/AzaThread

აღწერა

AzaThread გთავაზობთ მარტივ ინტერფეისს თემატური კლასების შესაქმნელად. რომლებიც რეალურად იყენებენ ცალკეულ პროცესებს ასინქრონულად მუშაობისთვის, მაგრამ ეს არ უნდა აინტერესებდეთ. თქვენ შეგიძლიათ გამოაგზავნოთ მოვლენები თემიდან, დააბრუნოთ შედეგები, გამოიყენოთ ერთი თემა მრავალჯერ და გადასცეთ მასში გაშვების არგუმენტები, ან შექმნათ 16 ძაფისგან შემდგარი აუზი, რომელიც აგროვებს თქვენს ამოცანებს, როგორიცაა ცხელი ნამცხვრები, ყოველგვარი ყურადღების მიქცევის გარეშე, რომ სამუშაო მიმდინარეობს სხვადასხვა ადგილას. პროცესები.

გარდა ამისა, შეგიძლიათ მარტივად შეამოწმოთ ბიბლიოთეკის მუშაობა სხვადასხვა რეჟიმში, ძაფების ოპტიმალური რაოდენობის არჩევით და პროცესებს შორის მონაცემების გადაცემის ოფციით, სპეციალურად თქვენი კონფიგურაციისთვის.

სრული მუშაობისთვის საჭიროა შემდეგი გაფართოებები: თავისუფალი, პოსიქსიდა pcntl.

ბიბლიოთეკა იყენებს LibEvent და დაწყვილებულ სოკეტებს პროცესებს შორის კომუნიკაციისთვის. მხარს უჭერს მონაცემთა გადაცემის 5 ვარიანტს (არგუმენტები, შედეგები და მოვლენის მონაცემები)!

მე წარმოგიდგენთ ოფციებს დაუყოვნებლივ შესრულების მონაცემებით. ტესტირებულია რვა ნაკადის აუზით Intel Core i7 2600K 3.40 Ghz-ზე (Ubuntu 11.04 VMware ვირტუალურ მანქანაზე). მოცემულია ტესტის 10 გამეორების საშუალო შედეგები jps-ში (სამუშაოები წამში - დავალებების რაოდენობა, რომლებიც უბრალოდ იღებენ არგუმენტებს და აგზავნიან მონაცემებს წამში).

სოკეტებთან მუშაობის გაფართოება ავტომატურად შეირჩევა. თუ ეს შესაძლებელია, გაფართოება გამოიყენება სოკეტები, რაც იძლევა გაუმჯობესებულ შესრულებას. წინააღმდეგ შემთხვევაში გამოყენებული იქნება ნაკადი.

ბავშვის პროცესი უსმენს ყველა ხელმისაწვდომ სიგნალს. ნაგულისხმევად, ყველა მათგანს (SIGWINCH-ისა და SIGINFO-ს გარდა) მოჰყვება გამორთვა. მაგრამ ამის მარტივად გადალახვა შესაძლებელია ძაფების კლასში მეთოდის შექმნით სიგნალის სახელით. Მაგალითად sigWinch.

მშობლის პროცესში, ყველა სიგნალი ასევე ჩაითვლება ნაგულისხმევად. ეს შეიძლება შეიცვალოს კლასის პარამეტრის დაყენებით listenMasterSignalsყალბი. ამ შემთხვევაში დამუშავდება მხოლოდ SIGCHLD. თქვენ შეგიძლიათ მარტივად დაამატოთ თქვენი საკუთარი დამმუშავებლები სტატიკური მეთოდის შექმნით, რომელსაც ეწოდება მ< имя сигнала > . Მაგალითად mSigTerm.

თუ ბავშვის პროცესი რაიმე მიზეზით იღუპება, კლასი ავტომატურად ჩაერთვება ახალი დავალების გაშვებისას. ეს ხდება შეუმჩნევლად და თქვენ საერთოდ არ გჭირდებათ ამაზე ფიქრი. ინსტანცია უბრალოდ არ საჭიროებს ხელახლა შექმნას რაიმე შეცდომის შემთხვევაში.

ბავშვის პროცესი პერიოდულად ამოწმებს მშობლის პროცესის არსებობას. თუ ის მოულოდნელად მოკვდება, ბავშვი ავტომატურად დასრულდება.

ძაფის ან ძაფის აუზის მიერ გამოყენებული ყველა რესურსი ავტომატურად იწმინდება დესტრუქტორის გამოძახებისას. მაგრამ მათი იძულებით გასუფთავება შესაძლებელია მეთოდის გამოძახებით გაწმენდა. ამ შემთხვევაში ძაფის/აუზის გამოყენება აღარ შეიძლება.

ზე სტანდარტული პარამეტრებითემა ინიციალიზებულია წინასწარ, კლასის შექმნისთანავე. თუ დააყენებთ პარამეტრს პრეფორკირომ false, მაშინ ჩანგალი მოხდება მხოლოდ ამოცანის გაშვების მომენტში.

ზოგადად, საკმაოდ ბევრი კონფიგურირებადი პარამეტრია. ბავშვის პროცესის სახელის შეცვლა ჩანგლის შემდეგ (პარამეტრი pNameკონსტრუქტორი), ვადა ამოცანის ხანგრძლივობისთვის ( timeoutWork), დროის ამოწურვა მაქსიმალური დროით, რომელსაც ბავშვის პროცესი შეუძლია დაელოდოს ამოცანებს ( დროის ამოწურვაMaxWait), ვადაა წინასწარი ინიციალიზაციის დრო ( timeoutInit), სოკეტის წაკითხვის ბუფერის ზომები ( pipeReadSize, pipeMasterReadSize).
თქვენ შეგიძლიათ გამორთოთ მრავალფუნქციური რეჟიმი ძაფებისთვის ( მრავალამოცანა). ამ შემთხვევაში, ყოველ ჯერზე, როდესაც დავალება სრულდება, ბავშვური პროცესი კვდება და კვლავ ჩანგალი იქნება შემდეგი გაშვებისთვის. ეს შესამჩნევად შეამცირებს შესრულებას.

კოდი დაფარულია ტესტებით და დეტალურად არის დოკუმენტირებული; გამოყენების მაგალითები შეგიძლიათ იხილოთ და გაუშვათ ფაილში მაგალითი.php.
მეტი რთული მაგალითებიშეცდომების დამუშავებით ჩანს ერთეულის ტესტის კოდში.

არსებობს გამართვის რეჟიმი, რომელშიც ძალიან დეტალური ინფორმაციაიმის შესახებ, თუ რა ხდება კონკრეტულად და სად.

გამოყენების მაგალითები

მთავარი მახასიათებელია მაქსიმალური სიმარტივე. თუ გსურთ რაღაცის გაშვება ცალკე "თეადში" საკმარისია შემდეგი კოდი:
class ExampleThread აფართოებს Thread ( დაცული ფუნქციის პროცესი() ( // ზოგიერთი სამუშაო აქ ) ) $thread = new ExampleThread(); $thread->wait()->run();
თუ ყველაფერია საჭირო სრულფასოვანი მუშაობისთვის, მაშინ დავალება შესრულდება ასინქრონულად. თუ არა, მაშინ ყველაფერი კვლავ იმუშავებს, მაგრამ სინქრონულ რეჟიმში.

პარამეტრის გადაცემით და შედეგის მიღებით, კოდი ოდნავ უფრო რთული გამოიყურება:
class ExampleThread აფართოებს Thread ( დაცული ფუნქციის პროცესი() ( return $this->getParam(0); ) ) $thread = new ExampleThread(); $thread->wait()->run(123); $result = $thread->wait()->getResult();

ანალოგიურად, ხელის ოდნავ ქნევით, ჩვენ ვამატებთ მოვლენის დამუშავებას ნაკადიდან:
class ExampleThread აფართოებს Thread ( const EV_PROCESS = "პროცესი"; დაცული ფუნქციის პროცესი() ( $events = $this->getParam(0); for ($i = 0; $i< $events; $i++) { $event_data = $i; $this->გამომწვევი (self::EV_PROCESS, $event_data); ) ) ) // დამატებითი არგუმენტი. $additionalArgument = 123; $thread->bind(ExampleThread::EV_PROCESS, ფუნქცია($event_name, $event_data, $additional_arg) ( // ღონისძიების დამუშავება), $additionalArgument); $მოვლენები = 10; // მოვლენების რაოდენობა, რომელსაც thread გამოიმუშავებს // იმისათვის, რომ თავიდან აიცილოთ ძაფს ხელით მოლოდინი პირველ გამოძახებამდე, // შეგიძლიათ გადაანაცვლოთ preforkWait თვისება TRUE-ზე შთამომავლობის კლასში $thread->wait(); $thread = new ExampleThread(); $thread->run($events)->wait();

და ბოლოს, რვა ძაფისგან შემდგარი ჯგუფის გამოყენებით, მუშაობის დროის შეცდომების დამუშავებით:
$threads = 8 // ძაფების რაოდენობა $pool = new ThreadPool("ExampleThread", $threads); $num = 25; // ამოცანების რაოდენობა $left = $num; // დარჩენილი ამოცანების რაოდენობა ( // თუ აუზში არის თავისუფალი ძაფები // და ჩვენ ჯერ კიდევ გვაქვს დავალებები შესასრულებელი ($pool->hasWaiting() && $left > 0) ( // დაწყებისას ვიღებთ თემის ID $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) ( foreach ($results როგორც $threadId => $result) ( / / წარმატებით დასრულებული დავალება // შედეგის იდენტიფიცირება შესაძლებელია // ნაკადის ID-ით ($threadId) $num--; ) ) თუ ($failed) ( // გაუმკლავდეს შესრულების შეცდომებს. // სამუშაო ითვლება წარუმატებლად დასრულებულად // თუ ბავშვის პროცესი მოკვდა შესრულების დროს ან // ამოიწურა დავალების შესრულების ვადა foreach ($ჩავარდა როგორც $threadId) ( $left++; ) ) ) while ($num > 0); // ყველა ბავშვის პროცესის შეწყვეტა. ჩვენ ვასუფთავებთ აუზის მიერ გამოყენებულ რესურსებს. $pool->cleanup();

შესრულების ტესტის შედეგები

მე ჩავატარე ტესტები ორ აპარატზე Ubuntu 11.04-ით.
პირველი არის Intel Core i3 540 3.07 Ghz
მეორე არის Intel Core i7 2600K 3.40 Ghz (Ubuntu მუშაობს VMware ვირტუალურ მანქანაზე)

მე უბრალოდ წარმოგიდგენთ შედეგებს, რათა შეაფასოთ პროდუქტიულობის ზრდა.
ისევ და ისევ, ეს არის საშუალო შედეგები 10 ტესტის გამეორების სერიის jps-ში (დავალებები წამში - ამოცანების რაოდენობა წამში).

როგორც დავალება, ძაფები ასრულებენ შემდეგ ნაგავს:
ამისთვის ($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 ჯერ ან მეტით, პროცესორის მიხედვით!

კოდი, რომელიც აწარმოებს ტესტების სერიას საჭირო პარამეტრებით, არის ფაილში examples/speed_test.php. ასე რომ თქვენ შეგიძლიათ მარტივად შეამოწმოთ შესრულება და აირჩიოთ ძაფების ოპტიმალური რაოდენობა თქვენთვის.

არსებობს საკმაოდ ბევრი გადაწყვეტილებები, რომლებიც მცურავია ინტერნეტში PHP-ში მრავალნაკადის ემულაციისთვის. ყველაზე ხშირად ისინი ეფუძნება ჩანგლებს, მაგრამ ასევე არსებობს ვარიაციები თემის გამოყენებით დახვევა, proc_openდა ასე შემდეგ.

ყველა ის ვარიანტი, რაც დამხვდა, ამა თუ იმ მიზეზის გამო არ მაწყობდა და ჩემი გადაწყვეტა მომიწია დამეწერა. მე მქონდა შემდეგი მოთხოვნები:

  • ჩანგლების გამოყენება;
  • სინქრონული რეჟიმი ინტერფეისის შენარჩუნებით საჭირო გაფართოებების არარსებობის შემთხვევაში;
  • ბავშვის პროცესების ხელახალი გამოყენება;
  • მონაცემთა სრული გაცვლა პროცესებს შორის. იმათ. გაუშვით არგუმენტებით და მიიღეთ შედეგი დასრულების შემდეგ;
  • მოვლენების გაცვლის შესაძლებლობა ბავშვის „ძაფის“ პროცესსა და ძირითად პროცესს შორის ოპერაციის დროს;
  • ძაფების აუზთან მუშაობა ხელახლა გამოყენების შენარჩუნებისას, არგუმენტების გაცემა და შედეგების მიღება;
  • მუშაობის დროის შეცდომების დამუშავება;
  • სამუშაოს შესრულების ვადები, ძაფით სამუშაოს მოლოდინი, ინიციალიზაცია;
  • მაქსიმალური შესრულება.

შედეგი იყო AzaThread ბიბლიოთეკა (ყოფილი CThread).

აღწერა

AzaThread გთავაზობთ მარტივ ინტერფეისს თემატური კლასების შესაქმნელად. რომლებიც რეალურად იყენებენ ცალკეულ პროცესებს ასინქრონულად მუშაობისთვის, მაგრამ ეს არ უნდა აინტერესებდეთ. შეგიძლიათ გამოაგზავნოთ მოვლენები თემიდან, დააბრუნოთ შედეგები, გამოიყენოთ ერთი თემა რამდენჯერმე, გადასცეთ მას დაწყების არგუმენტები, ან შექმნათ 16 თემის ფონდი, რომელიც აგროვებს თქვენს ამოცანებს, როგორიცაა ცხელი ნამცხვრები, ყურადღების მიქცევის გარეშე, რომ სამუშაო მიმდინარეობს. სხვადასხვა პროცესებში.

გარდა ამისა, თქვენ შეგიძლიათ მარტივად შეამოწმოთ ბიბლიოთეკის მუშაობა სხვადასხვა რეჟიმებში ძაფების ოპტიმალური რაოდენობის არჩევით და პროცესებს შორის მონაცემების გადაცემის შესაძლებლობით, სპეციალურად თქვენი კონფიგურაციისთვის.

სრული მუშაობისთვის საჭიროა შემდეგი გაფართოებები: თავისუფალი, პოსიქსიდა pcntl.

ბიბლიოთეკა იყენებს LibEvent და დაწყვილებულ სოკეტებს პროცესებს შორის კომუნიკაციისთვის. მხარს უჭერს მონაცემთა გადაცემის 5 ვარიანტს (არგუმენტები, შედეგები და მოვლენის მონაცემები)!

მე წარმოგიდგენთ ოფციებს დაუყოვნებლივ შესრულების მონაცემებით. ტესტირებულია რვა ნაკადის აუზით Intel Core i7 2600K 3.40 Ghz-ზე (Ubuntu 11.04 VMware ვირტუალურ მანქანაზე). მოცემულია ტესტის 10 გამეორების საშუალო შედეგები jps-ში (სამუშაოები წამში - ამოცანების რაოდენობა, რომლებიც უბრალოდ იღებენ არგუმენტებს და აგზავნიან მონაცემებს წამში).

სოკეტებთან მუშაობის გაფართოება ავტომატურად შეირჩევა. თუ ეს შესაძლებელია, გაფართოება გამოიყენება სოკეტები, რაც იძლევა გაუმჯობესებულ შესრულებას. წინააღმდეგ შემთხვევაში გამოყენებული იქნება ნაკადი.

ბავშვის პროცესი უსმენს ყველა ხელმისაწვდომ სიგნალს. ნაგულისხმევად, ყველა მათგანს (SIGWINCH-ისა და SIGINFO-ს გარდა) მოჰყვება გამორთვა. მაგრამ ამის მარტივად გადალახვა შესაძლებელია ძაფების კლასში მეთოდის შექმნით სიგნალის სახელით. მაგალითად sigWinch.

მშობლის პროცესში, ყველა სიგნალი ასევე ჩაითვლება ნაგულისხმევად. ეს შეიძლება შეიცვალოს კლასის პარამეტრის listenMasterSignals false-ზე დაყენებით. ამ შემთხვევაში დამუშავდება მხოლოდ SIGCHLD. თქვენ შეგიძლიათ მარტივად დაამატოთ თქვენი საკუთარი დამმუშავებლები სტატიკური მეთოდის შექმნით, სახელწოდებით m<имя сигнала>. მაგალითად, mSigTerm.

თუ ბავშვის პროცესი რაიმე მიზეზით იღუპება, ახალი დავალების გაშვებისას კლასი ავტომატურად წყდება. ეს ხდება შეუმჩნევლად და თქვენ საერთოდ არ გჭირდებათ ამაზე ფიქრი. ინსტანცია უბრალოდ არ საჭიროებს ხელახლა შექმნას რაიმე შეცდომის შემთხვევაში.

ბავშვის პროცესი პერიოდულად ამოწმებს მშობლის პროცესის არსებობას. თუ ის მოულოდნელად მოკვდება, ბავშვი ავტომატურად დასრულდება.

ძაფის ან ძაფის აუზის მიერ გამოყენებული ყველა რესურსი ავტომატურად იწმინდება დესტრუქტორის გამოძახებისას. მაგრამ მათი იძულებით გაწმენდა შესაძლებელია გაწმენდის მეთოდის გამოძახებით. ამ შემთხვევაში ძაფის/აუზის გამოყენება აღარ შეიძლება.

სტანდარტული პარამეტრებით, თემა ინიციალიზდება წინასწარ, კლასის შექმნისთანავე. თუ თქვენ დააყენებთ prefork პარამეტრს false-ზე, მაშინ ჩანგალი მოხდება მხოლოდ ამოცანის გაშვების მომენტში.

ზოგადად, საკმაოდ ბევრი კონფიგურირებადი პარამეტრია. ბავშვის პროცესის სახელის შეცვლა ჩანგლის შემდეგ (კონსტრუქტორის პარამეტრი pName), დავალების შესრულების ხანგრძლივობის ვადა (timeoutWork), ვადა იმ მაქსიმალური დროის განმავლობაში, როდესაც ბავშვი პროცესი ელოდება ამოცანებს (timeoutMaxWait), ვადა ინიციალიზაციის დრო (timeoutInit), ბუფერების ზომა სოკეტების წასაკითხად (pipeReadSize, pipeMasterReadSize). შეგიძლიათ გამორთოთ მულტიამოცანის რეჟიმი ძაფებისთვის (მრავალამოცანა). ამ შემთხვევაში, ყოველ ჯერზე, როდესაც დავალება სრულდება, ბავშვური პროცესი კვდება და კვლავ ჩანგალი იქნება შემდეგი გაშვებისთვის. ეს შესამჩნევად შეამცირებს შესრულებას.

კოდი დაფარულია ტესტებით და დეტალურად არის დოკუმენტირებული; გამოყენების მაგალითები შეგიძლიათ ნახოთ და გაუშვათ example.php ფაილში. შეცდომების დამუშავების უფრო რთული მაგალითები შეგიძლიათ იხილოთ ერთეულის ტესტის კოდში.

არსებობს გამართვის რეჟიმი, რომელიც აჩვენებს ძალიან დეტალურ ინფორმაციას იმის შესახებ, თუ რა ხდება ზუსტად და სად.

გამოყენების მაგალითები

მთავარი მახასიათებელია მაქსიმალური სიმარტივე. თუ გსურთ რაიმეს გაშვება ცალკე "თედში" საკმარისია შემდეგი კოდი:

კლასი ExampleThread აფართოებს Thread ( დაცული ფუნქციის პროცესი() ( // ზოგიერთი სამუშაო აქ ) ) $thread = new ExampleThread(); $thread->wait()->run();

თუ ყველაფერია საჭირო სრულფასოვანი მუშაობისთვის, მაშინ დავალება შესრულდება ასინქრონულად. თუ არა, მაშინ ყველაფერი კვლავ იმუშავებს, მაგრამ სინქრონულ რეჟიმში.

პარამეტრის გადაცემით და შედეგის მიღებით, კოდი ოდნავ უფრო რთული გამოიყურება:

Class ExampleThread აფართოებს Thread ( დაცული ფუნქციის პროცესი() ( return $this->getParam(0); ) ) $thread = new ExampleThread(); $thread->wait()->run(123); $result = $thread->wait()->getResult();

ანალოგიურად, ხელის ოდნავ ქნევით, ჩვენ ვამატებთ მოვლენის დამუშავებას ნაკადიდან:

Class ExampleThread აფართოებს Thread ( const EV_PROCESS = "პროცესი"; დაცული ფუნქციის პროცესი() ( $events = $this->getParam(0); for ($i = 0; $i ტრიგერი(self::EV_PROCESS, $event_data); ) ) ) // დამატებითი არგუმენტი. $additionalArgument = 123; $thread->bind(ExampleThread::EV_PROCESS, ფუნქცია($event_name, $event_data, $additional_arg) ( // ღონისძიების დამუშავება), $additionalArgument); $მოვლენები = 10; // მოვლენების რაოდენობა, რომელსაც thread გამოიმუშავებს // იმისათვის, რომ თავიდან აიცილოთ ძაფს ხელით მოლოდინი პირველ გამოძახებამდე, // შეგიძლიათ გადაანაცვლოთ preforkWait თვისება TRUE-ზე შთამომავლობის კლასში $thread->wait(); $thread = new ExampleThread(); $thread->run($events)->wait();

და ბოლოს, რვა ძაფისგან შემდგარი ჯგუფის გამოყენებით, მუშაობის დროის შეცდომების დამუშავებით:

$threads = 8 // ძაფების რაოდენობა $pool = new ThreadPool("ExampleThread", $threads); $num = 25; // ამოცანების რაოდენობა $left = $num; // დარჩენილი ამოცანების რაოდენობა ( // თუ აუზში არის თავისუფალი ძაფები // და ჩვენ ჯერ კიდევ გვაქვს დავალებები შესასრულებელი ($pool->hasWaiting() && $left > 0) ( // დაწყებისას ვიღებთ თემის ID $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) ( foreach ($results როგორც $threadId => $result) ( / / წარმატებით დასრულებული დავალება // შედეგის იდენტიფიცირება შესაძლებელია // ნაკადის ID-ით ($threadId) $num--; ) ) თუ ($failed) ( // გაუმკლავდეს შესრულების შეცდომებს. // სამუშაო ითვლება წარუმატებლად დასრულებულად // თუ ბავშვის პროცესი მოკვდა შესრულების დროს ან // ამოიწურა დავალების შესრულების ვადა foreach ($ჩავარდა როგორც $threadId) ( $left++; ) ) ) while ($num > 0); // ყველა ბავშვის პროცესის შეწყვეტა. ჩვენ ვასუფთავებთ აუზის მიერ გამოყენებულ რესურსებს. $pool->cleanup();

შესრულების ტესტის შედეგები

მე ჩავატარე ტესტები ორ აპარატზე Ubuntu 11.04-ით.
პირველი არის Intel Core i3 540 3.07 Ghz.
მეორე არის Intel Core i7 2600K 3.40 Ghz (Ubuntu მუშაობს VMware ვირტუალურ მანქანაზე).

მე უბრალოდ წარმოგიდგენთ შედეგებს, რათა შეაფასოთ პროდუქტიულობის ზრდა. ისევ და ისევ, ეს არის საშუალო შედეგები ტესტის 10 გამეორების სერიის jps-ში (სამუშაოები წამში - ამოცანების რაოდენობა წამში).

როგორც დავალება, ძაფები ასრულებენ შემდეგ ნაგავს:

ამისთვის ($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 ჯერ ან მეტით, პროცესორის მიხედვით!

კოდი, რომელიც აწარმოებს ტესტების სერიას საჭირო პარამეტრებით, არის ფაილში examples/speed_test.php. ასე რომ თქვენ შეგიძლიათ მარტივად შეამოწმოთ შესრულება და აირჩიოთ ძაფების ოპტიმალური რაოდენობა თქვენთვის.

ძალიან გამიხარდება, თუ ბიბლიოთეკა ვინმეს გამოადგება. ნებისმიერი ფუნქციის მოთხოვნა ან აღმოჩენილი ხარვეზი შეიძლება დარჩეს Github-ზე, მე დაუყოვნებლივ გამოვასწორებ და გავაუმჯობესებ ბიბლიოთეკას.

როგორც ჩანს, PHP დეველოპერები იშვიათად იყენებენ კონკურენტულობას. მე არ ვისაუბრებ სინქრონული კოდის სიმარტივეზე; ერთი ხრახნიანი პროგრამირება, რა თქმა უნდა, უფრო მარტივი და ნათელია, მაგრამ ზოგჯერ პარალელურობის მცირე გამოყენებამ შეიძლება გამოიწვიოს შესრულების შესამჩნევი ზრდა.

ამ სტატიაში ჩვენ გადავხედავთ, თუ როგორ შეიძლება მიღწეული იყოს მრავალძაფიანი PHP-ში pthreads გაფართოების გამოყენებით. ამისათვის საჭიროა 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 კლასი ახალი თემის შესაქმნელად და ცალკე ძაფზე გარკვეული დამუშავების გასაშვებად.

Მაგალითად:

$task = ახალი კლასი აფართოებს თემას ( პირადი $response; საჯარო ფუნქციის გაშვება() ( $content = file_get_contents ("http://google.com"); preg_match ("~ (.+)~", $content, $matches); $this->response = $matches; )); $task->start() && $task->join(); var_dump($task->response); // string (6) "გუგლი"

აქ Run მეთოდი არის ჩვენი დამუშავება, რომელიც შესრულდება ახალი თემის შიგნით. როდესაც Thread::start გამოიძახება, ახალი თემა წარმოიქმნება და გამოიძახება run მეთოდი. ჩვენ შემდეგ ვუერთებთ შვილო ძაფს მთავარ ძაფში Thread::join-ის გამოძახებით, რომელიც დაიბლოკება მანამ, სანამ ბავშვური თემა არ დასრულდება. ეს უზრუნველყოფს დავალების შესრულებას მანამ, სანამ ჩვენ შევეცდებით შედეგის დაბეჭდვას (რომელიც ინახება $task->response-ში).

შეიძლება არ იყოს სასურველი კლასის დაბინძურება დამატებითი პასუხისმგებლობებით, რომლებიც დაკავშირებულია ნაკადის ლოგიკასთან (მათ შორის, გაშვების მეთოდის განსაზღვრის პასუხისმგებლობა). ჩვენ შეგვიძლია განვასხვავოთ ასეთი კლასები Threaded კლასიდან მათი მემკვიდრეობით. შემდეგ მათი გაშვება შესაძლებელია სხვა ძაფში:

Class Task აფართოებს Threaded ( საჯარო $response; საჯარო ფუნქცია someWork() ( $content = file_get_contents ("http://google.com"); preg_match ("~ (.+) ~", $content, $matches); $ this->response = $matches; ) ) $task = ახალი ამოცანა; $thread = new class($task) აფართოებს Thread ( კერძო $task; საჯარო ფუნქცია __construct (Threaded $task) ( $this->task = $task; ) საჯარო ფუნქცია run() ( $this->task->someWork( );)); $thread->start() && $thread->join(); var_dump($task->response);

ნებისმიერი კლასი, რომელიც უნდა გაიაროს ცალკე თემაში უნდამემკვიდრეობა Threaded კლასიდან. ეს იმიტომ ხდება, რომ ის უზრუნველყოფს აუცილებელ შესაძლებლობებს სხვადასხვა ძაფებზე დამუშავების შესასრულებლად, ასევე იმპლიციტურ უსაფრთხოებასა და სასარგებლო ინტერფეისებს (როგორიცაა რესურსების სინქრონიზაცია).

მოდით შევხედოთ კლასის იერარქიას, რომელსაც გვთავაზობს pthreads გაფართოება:

Threaded (ახორციელებს Traversable, Collectable) Thread Worker Volatile Pool

ჩვენ უკვე გავაშუქეთ და ვისწავლეთ Thread და Threaded კლასების საფუძვლები, ახლა მოდით გადავხედოთ დანარჩენ სამს (Worker, Volatile და Pool).

ძაფების ხელახალი გამოყენება

ახალი თემის დაწყება თითოეული ამოცანისთვის, რომელიც პარალელიზებას საჭიროებს, საკმაოდ ძვირია. ეს იმიტომ ხდება, რომ საერთო-არაფრის არქიტექტურა უნდა განხორციელდეს pthread-ებში, რათა მივაღწიოთ მრავალნაკადს PHP-ში. რაც ნიშნავს, რომ PHP თარჯიმანის მიმდინარე ინსტანციის მთელი შესრულების კონტექსტი (ყველა კლასის, ინტერფეისის, მახასიათებლისა და ფუნქციის ჩათვლით) უნდა იყოს კოპირებული თითოეული შექმნილი ძაფისთვის. იმის გამო, რომ ამას აქვს შესამჩნევი გავლენა შესრულებაზე, ნაკადი ყოველთვის უნდა იქნას გამოყენებული, როდესაც ეს შესაძლებელია. ძაფების ხელახლა გამოყენება შესაძლებელია ორი გზით: Workers ან Pools-ის გამოყენებით.

Worker კლასი გამოიყენება რიგი ამოცანების სინქრონულად შესასრულებლად სხვა თემაში. ეს კეთდება ახალი Worker ინსტანციის შექმნით (რომელიც ქმნის ახალ თემას) და შემდეგ ამოცანების გადატანით ცალკე thread-ის სტეკზე (Work::stack-ის გამოყენებით).

აი პატარა მაგალითი:

Class Task აფართოებს Threaded ( კერძო $value; საჯარო ფუნქცია __construct(int $i) ( $this->value = $i; ) საჯარო ფუნქცია run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $worker = new Worker(); $worker->start(); for ($i = 0; $i stack(new Task($i)); ) while ($worker->collect()); $worker->shutdown();

ზემოთ მოყვანილ მაგალითში, $worker ობიექტის 15 დავალება გადატანილია სტეკზე Worker::stack მეთოდის მეშვეობით, და შემდეგ ისინი მუშავდება იმ თანმიმდევრობით, როგორც იქნა დაყენებული. Worker::collect მეთოდი, როგორც ზემოთ არის ნაჩვენები, გამოიყენება ამოცანების გასასუფთავებლად, როგორც კი ისინი დასრულდება. მასთან ერთად, while მარყუჟის შიგნით, ჩვენ ვბლოკავთ მთავარ თემას, სანამ სტეკის ყველა დავალება არ დასრულდება და გასუფთავდება - სანამ Worker::shutdown-ს დავუძახებთ. მუშაკის ნაადრევად შეწყვეტა (ანუ სანამ ჯერ კიდევ არის შესასრულებელი ამოცანები) კვლავ დაბლოკავს მთავარ თემას, სანამ ყველა დავალება არ დაასრულებს მათ შესრულებას, უბრალოდ, რომ ამოცანები არ შეგროვდეს ნაგავი (რაც გულისხმობს მეხსიერების გაჟონვას).

Worker კლასი გთავაზობთ რამდენიმე სხვა მეთოდს, რომლებიც დაკავშირებულია მის ამოცანების დასტასთან, მათ შორის Worker::unstack ბოლო stacked ამოცანის ამოსაღებად და Worker::getStacked ამოცანების რაოდენობის მისაღებად შესრულების სტეკში. მუშათა დასტა შეიცავს მხოლოდ დავალებებს, რომლებიც უნდა შესრულდეს. მას შემდეგ, რაც დასტაზე დავალება დასრულდება, ის ამოღებულია და მოთავსებულია ცალკე (შიდა) დასტაზე ნაგვის შეგროვებისთვის (Work::collect მეთოდის გამოყენებით).

ძაფების ხელახლა გამოყენების კიდევ ერთი გზა მრავალ ამოცანებში არის thread pool-ის გამოყენება (Pool კლასის მეშვეობით). ძაფების ფონდი იყენებს მუშათა ჯგუფს დავალებების შესასრულებლად ერთდროულად, რომელშიც კონკურენტულობის კოეფიციენტი (აუზის ძაფების რაოდენობა, რომლითაც ის მუშაობს) დაყენებულია აუზის შექმნისას.

მოდით მოვარგოთ ზემოხსენებული მაგალითი მუშათა ჯგუფის გამოსაყენებლად:

Class Task აფართოებს Threaded ( კერძო $value; საჯარო ფუნქცია __construct(int $i) ( $this->value = $i; ) საჯარო ფუნქცია run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $pool = new Pool(4); for ($i = 0; $i გაგზავნა(ახალი ამოცანა($i)); ) while ($pool->collect()); $pool->shutdown();

არსებობს რამდენიმე შესამჩნევი განსხვავება მუშისგან განსხვავებით აუზის გამოყენებისას. პირველი, აუზი არ საჭიროებს ხელით გაშვებას; ის იწყებს ამოცანების შესრულებას, როგორც კი ისინი ხელმისაწვდომი გახდება. მეორეც, ჩვენ გაგზავნაამოცანები აუზზე, არა მოათავსეთ ისინი დასტაზე. გარდა ამისა, Pool კლასი არ იღებს მემკვიდრეობას Threaded-დან და, შესაბამისად, არ შეიძლება გადავიდეს სხვა ძაფებზე (განსხვავებით Worker-ისგან).

Როგორ კარგი პრაქტიკამუშაკებისთვის და აუზებისთვის, თქვენ ყოველთვის უნდა გაასუფთაოთ მათი ამოცანები, როგორც კი ისინი დაასრულებენ, შემდეგ კი ხელით შეწყვიტოთ ისინი. Thread კლასის გამოყენებით შექმნილი ძაფები ასევე უნდა დაერთოს მშობელ ძაფს.

ძაფები და (არა) ცვალებადობა

ბოლო კლასი, რომელსაც შევეხებით არის Volatile, ახალი დამატება pthreads v3. უცვლელობა გახდა მნიშვნელოვანი კონცეფცია თრეადებში, რადგან მის გარეშე შესრულება მნიშვნელოვნად ზარალდება. ამიტომ, ნაგულისხმევად, Threaded კლასების თვისებები, რომლებიც თავად არიან Threaded ობიექტები, ახლა უცვლელია და, შესაბამისად, მათი გადაწერა შეუძლებელია მათი საწყისი მინიჭების შემდეგ. ასეთი თვისებების აშკარა ცვალებადობა ამჟამად სასურველია და მისი მიღწევა მაინც შესაძლებელია ახალი არასტაბილური კლასის გამოყენებით.

მოდით შევხედოთ მაგალითს, რომელიც აჩვენებს უცვლელობის ახალ შეზღუდვებს:

Class Task აფართოებს Threaded // Threaded კლასს ( საჯარო ფუნქცია __construct() ( $this->data = new Threaded(); // $this->მონაცემები არ არის გადაწერილი, რადგან ეს არის Threaded თვისება Threaded კლასის ) ) $task = new class(new Task()) აფართოებს Thread-ს ( // a Threaded კლასს, ვინაიდან Thread აფართოებს Threaded საჯარო ფუნქციას __construct($tm) ($this->threadedMember = $tm; var_dump($this->threadedMember-> მონაცემები);// ობიექტი (Threaded)#3 (0) () $this->threadedMember = new StdClass(); // არასწორია, რადგან თვისება არის Threaded წევრი კლასის ) );

მეორეს მხრივ, არასტაბილური კლასების ხრახნიანი თვისებები ცვალებადია:

Class Task აფართოებს Volatile ( საჯარო ფუნქცია __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); // ობიექტი(stdClass)#4 (0) () // ჯერ კიდევ არასწორია, რადგან Volatile აფართოებს Threaded-ს, ამიტომ თვისება კვლავ არის Threaded კლასის $this->volatileMember = new StdClass(); ) );

ჩვენ ვხედავთ, რომ Volatile კლასი არღვევს უცვლელობას, რომელიც დაწესებულია მისი მშობელი Threaded კლასის მიერ, რათა უზრუნველყოს Threaded თვისებების შეცვლის შესაძლებლობა (ასევე მათი unset()).

ცვალებადობისა და Volatile კლასის გასაშუქებლად არის კიდევ ერთი განხილვის საგანი - მასივები. pthread-ებში მასივები ავტომატურად გადაიცემა Volatile ობიექტებზე Threaded კლასის თვისებებზე მინიჭებისას. ეს იმიტომ ხდება, რომ უბრალოდ არ არის უსაფრთხო მრავალი PHP კონტექსტის მასივის მანიპულირება.

მოდი კიდევ ერთხელ გადავხედოთ მაგალითს, რომ უკეთ გავიგოთ ზოგიერთი რამ:

$მასივი = ; $task = new class($array) აფართოებს Thread-ს ( კერძო $data; საჯარო ფუნქცია __construct (მასივი $array) ( $this->data = $array; ) საჯარო ფუნქცია 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 კლასი გვაწვდის ისეთ ოპერაციებს, როგორიცაა ჩაშენებული მეთოდები.

როგორც დემონსტრირება:

$data = ახალი კლასი ვრცელდება Volatile ( საჯარო $a = 1; საჯარო $b = 2; საჯარო $c = 3; ); var_dump ($მონაცემები); var_dump($data->pop()); var_dump($data->shift()); var_dump ($მონაცემები); /* გამომავალი: ობიექტი(კლასი@ანონიმური)#1 (3) ( ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ) int(3) int(1) ობიექტი(class@anonymous)#1 (1) ( ["b"]=> int(2) ) */

სხვა მხარდაჭერილი ოპერაციები მოიცავს Threaded::chunk და Threaded::merge .

სინქრონიზაცია

ამ სტატიის ბოლო ნაწილში ჩვენ განვიხილავთ სინქრონიზაციას pthread-ებში. სინქრონიზაცია არის მეთოდი, რომელიც საშუალებას გაძლევთ გააკონტროლოთ წვდომა გაზიარებულ რესურსებზე.

მაგალითად, მოდით განვახორციელოთ მარტივი მრიცხველი:

$counter = ახალი კლასი აფართოებს 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 = ახალი კლასი ვრცელდება Thread ( public $i = 0; public function run() ( $this->synchronized(function () ( for ($i = 0; $i i; ) )); ) ); $counter->start(); $counter->synchronized(function ($counter) ( for ($i = 0; $i i; ) ), $counter); $counter->join(); var_dump($counter->i); // int(20)

სინქრონიზებული კოდის ბლოკებს ასევე შეუძლიათ ერთმანეთთან კომუნიკაცია Threaded::wait და Threaded::notify (ან Threaded::notifyAll) მეთოდების გამოყენებით.

აქ არის ალტერნატიული ზრდა ორ სინქრონიზებულ ციკლში:

$counter = ახალი კლასი აგრძელებს Thread-ს ( საჯარო $cond = 1; საჯარო ფუნქცია run() ( $this->synchronized(function () ( for ($i = 0; $i notify(); if ($this->cond === 1) ( $this->cond = 2; $this->wait(); ) ) )); ) ); $counter->start(); $counter->synchronized(function ($counter) ( if ($counter->cond !== 2) ( $counter->wait(); // ელოდე სთვისსხვა უნდა დაიწყოს პირველი ) for ($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-ში მოკლე მიმოხილვამხარდაჭერილი სინქრონიზაციის შესაძლებლობები. ამ საფუძვლების დანერგვით, ახლა შეგვიძლია დავიწყოთ იმის გარკვევა, თუ როგორ შეიძლება თრეადების გამოყენება რეალურ სამყაროში! ეს იქნება ჩვენი შემდეგი პოსტის თემა.

თუ გაინტერესებთ შემდეგი პოსტის თარგმანი, შემატყობინეთ: კომენტარი გააკეთეთ სოციალურ მედიაში. ქსელები, მხარი დაუჭირეთ და გაუზიარეთ პოსტი კოლეგებსა და მეგობრებს.

Ჩატვირთვა...Ჩატვირთვა...