PHP มีเธรดหรือไม่?


130

ฉันพบแพ็คเกจ PECL ที่เรียกว่าเธรดแต่ยังไม่มีการเปิดตัว และไม่มีอะไรเกิดขึ้นบนเว็บไซต์ PHP


ใครทราบว่า ( pcntl_fork()) จะใช้งานได้หรือไม่ถ้าเรียกจาก Apache?
Josh K

มันเก่ามากอย่างไม่น่าเชื่อ แต่ฉันมีคำตอบที่ให้เธรดใน php (ดูลิงก์ด้านล่าง)
Alec Gorge

พวกเขาไม่แนะนำให้เรียกใช้ fork จากสภาพแวดล้อมเซิร์ฟเวอร์ ฉันไม่โทษพวกเขา อย่างไรก็ตาม pcntl_fork ดูเหมือนจะเป็นทางออกที่ดีที่สุดสำหรับการทำเธรด PHP
just_wes

ใช่คุณไม่จำเป็นต้องแยกกระบวนการ php apache2
andho

2
ใช้pthreadsทำงานอย่างมีเสน่ห์
Baba

คำตอบ:


40

ไม่มีสิ่งใดที่ฉันรับรู้ได้ สิ่งที่ดีที่สุดต่อไปคือการให้สคริปต์หนึ่งรันอีกตัวหนึ่งผ่าน CLI แต่นั่นเป็นพื้นฐานเล็กน้อย ขึ้นอยู่กับสิ่งที่คุณกำลังพยายามทำและความซับซ้อนนี้อาจเป็นตัวเลือกหรือไม่ก็ได้


1
นั่นคือสิ่งที่ฉันคิดว่า. ฉันเห็นโพสต์เก่า ๆ มากมายบอกว่าไม่และไม่มีอะไรใน php.net นี่คือความคิดของฉัน ขอบคุณที่ยืนยัน
Thomas Owens

2
ใช่แพคเกจ PECL นั้นเป็นเรื่องหยอกล้อ - ฉันวิ่งข้ามมันเช่นกัน แต่ก็ไม่มีอะไรเกิดขึ้น
Wilco

180

จากคู่มือ PHP สำหรับส่วนขยายpthreads :

pthreads เป็น Object Orientated API ที่อนุญาตให้ผู้ใช้เชื่อมโยงหลายเธรดใน PHP ประกอบด้วยเครื่องมือทั้งหมดที่คุณต้องการเพื่อสร้างแอปพลิเคชันแบบมัลติเธรดที่กำหนดเป้าหมายที่เว็บหรือคอนโซล แอปพลิเคชัน PHP สามารถสร้างอ่านเขียนดำเนินการและซิงโครไนซ์กับ Threads, Workers และ Stackables

ไม่น่าเชื่อเท่าที่ฟังมามันเป็นความจริงทั้งหมด วันนี้ PHP สามารถมัลติเธรดสำหรับผู้ที่ต้องการลองใช้งาน

PHP4 รุ่นแรกเมื่อวันที่ 22 พฤษภาคม พ.ศ. 2543 PHP ได้รับการจัดส่งมาพร้อมกับสถาปัตยกรรมที่ปลอดภัยของเธรดซึ่งเป็นวิธีการดำเนินการหลายอินสแตนซ์ของล่ามในเธรดที่แยกจากกันในสภาพแวดล้อม SAPI (Server API) แบบมัลติเธรด ในช่วง 13 ปีที่ผ่านมาการออกแบบสถาปัตยกรรมนี้ได้รับการบำรุงรักษาและขั้นสูง: ได้รับการใช้งานจริงบนเว็บไซต์ที่ใหญ่ที่สุดในโลกนับตั้งแต่นั้นเป็นต้นมา

การทำเธรดในพื้นที่ของผู้ใช้ไม่เคยเป็นปัญหาสำหรับทีม PHP และยังคงเป็นเช่นนั้นมาจนถึงทุกวันนี้ คุณควรเข้าใจว่าในโลกที่ PHP ทำธุรกิจนั้นมีวิธีการปรับขนาดที่กำหนดไว้แล้ว - เพิ่มฮาร์ดแวร์ ในช่วงหลายปีที่ผ่านมามีการใช้ PHP ฮาร์ดแวร์มีราคาถูกลงเรื่อย ๆ สิ่งนี้จึงไม่ค่อยเป็นที่กังวลสำหรับทีม PHP ในขณะที่ราคาถูกลง แต่ก็มีประสิทธิภาพมากขึ้นด้วย วันนี้โทรศัพท์มือถือและแท็บเล็ตของเรามีสถาปัตยกรรมแบบดูอัลและควอดคอร์และมีแรมให้ใช้งานมากมายเดสก์ท็อปและเซิร์ฟเวอร์ของเรามักจะมี 8 หรือ 16 คอร์, 16 และ 32 กิกะไบต์ของแรมแม้ว่าเราอาจจะไม่สามารถมีสอง ภายในงบประมาณและการมีเดสก์ท็อปสองเครื่องแทบจะไม่มีประโยชน์สำหรับพวกเราส่วนใหญ่

นอกจากนี้ PHP ถูกเขียนขึ้นสำหรับผู้ที่ไม่ใช่โปรแกรมเมอร์ซึ่งเป็นภาษาพื้นเมืองของมือสมัครเล่นหลายคน เหตุผลที่ PHP ถูกนำมาใช้อย่างง่ายดายเนื่องจากเป็นภาษาที่ง่ายต่อการเรียนรู้และเขียน เหตุผลที่ PHP มีความน่าเชื่อถือในปัจจุบันเป็นเพราะงานจำนวนมากที่เกี่ยวข้องกับการออกแบบและทุก ๆ การตัดสินใจของกลุ่ม PHP ความน่าเชื่อถือและความยิ่งใหญ่ที่แท้จริงทำให้มันอยู่ในจุดอับสายตาหลังจากผ่านไปหลายปี ที่คู่แข่งล้มลงตามกาลเวลาหรือกดดัน

การเขียนโปรแกรมแบบหลายเธรดไม่ใช่เรื่องง่ายสำหรับคนส่วนใหญ่แม้ว่าจะมี API ที่สอดคล้องกันและเชื่อถือได้มากที่สุด แต่ก็ยังมีสิ่งต่างๆที่ต้องคิดและความเข้าใจผิดมากมาย กลุ่ม PHP ไม่ต้องการให้ผู้ใช้เชื่อมโยงหลายเธรดเป็นคุณสมบัติหลักจึงไม่เคยได้รับความสนใจอย่างจริงจังและถูกต้อง PHP ไม่ควรซับซ้อนสำหรับทุกคน

ทุกสิ่งที่พิจารณาแล้วยังมีประโยชน์ที่จะได้รับจากการอนุญาตให้ PHP ใช้ประโยชน์จากคุณสมบัติที่พร้อมใช้งานจริงและผ่านการทดสอบแล้วเพื่อให้สามารถใช้ประโยชน์สูงสุดจากสิ่งที่เรามีเมื่อการเพิ่มมากขึ้นไม่ใช่ตัวเลือกเสมอไปและสำหรับจำนวนมาก ของงานไม่จำเป็นจริงๆ

pthreads ประสบความสำเร็จสำหรับผู้ที่ต้องการสำรวจ API ที่อนุญาตให้ผู้ใช้แอปพลิเคชัน PHP แบบหลายเธรด API นี้อยู่ระหว่างดำเนินการและกำหนดระดับความเสถียรและความสมบูรณ์ของเบต้า

เป็นความรู้ทั่วไปว่าไลบรารี PHP บางตัวใช้ไม่ปลอดภัยกับเธรดควรชัดเจนสำหรับโปรแกรมเมอร์ว่า pthreads ไม่สามารถเปลี่ยนแปลงสิ่งนี้ได้และไม่พยายามที่จะลอง อย่างไรก็ตามไลบรารีใด ๆ ที่มีเธรดปลอดภัยสามารถใช้งานได้เช่นเดียวกับการตั้งค่าเธรดอื่น ๆ ที่ปลอดภัยของล่าม

pthreads ใช้ Posix Threads (แม้กระทั่งใน Windows) สิ่งที่โปรแกรมเมอร์สร้างขึ้นคือเธรดการดำเนินการจริง แต่เพื่อให้เธรดเหล่านั้นมีประโยชน์พวกเขาต้องตระหนักถึง PHP - สามารถรันโค้ดผู้ใช้แชร์ตัวแปรและอนุญาตวิธีการสื่อสารที่เป็นประโยชน์ (การซิงโครไนซ์). ดังนั้นทุกเธรดจึงถูกสร้างขึ้นด้วยอินสแตนซ์ของตัวแปล แต่ด้วยการออกแบบตัวแปลนั้นถูกแยกออกจากอินสแตนซ์อื่น ๆ ของล่ามเช่นเดียวกับสภาพแวดล้อม API ของเซิร์ฟเวอร์แบบหลายเธรด pthreads พยายามที่จะเชื่อมช่องว่างด้วยวิธีที่ดีและปลอดภัย ความกังวลหลายอย่างของโปรแกรมเมอร์ของเธรดใน C ไม่ได้มีไว้สำหรับโปรแกรมเมอร์ของ pthreads โดยการออกแบบ pthreads จะคัดลอกเมื่ออ่านและคัดลอกเมื่อเขียน (RAM มีราคาถูก) ดังนั้นจึงไม่มีสองอินสแตนซ์ที่จัดการข้อมูลทางกายภาพเดียวกัน แต่ทั้งสองอย่างอาจส่งผลต่อข้อมูลในเธรดอื่น

ทำไมต้องคัดลอกในการอ่านและคัดลอกเมื่อเขียน:

public function run() {
    ...
    (1) $this->data = $data;
    ...
    (2) $this->other = someOperation($this->data);
    ...
}

(3) echo preg_match($pattern, $replace, $thread->data);

(1) ในขณะที่ล็อคการอ่านและการเขียนถูกเก็บไว้บนที่เก็บข้อมูลอ็อบเจ็กต์ pthreads ข้อมูลจะถูกคัดลอกจากตำแหน่งเดิมในหน่วยความจำไปยังที่เก็บอ็อบเจ็กต์ pthreads ไม่ได้ปรับการอ้างอิงของตัวแปร Zend สามารถปลดปล่อยข้อมูลเดิมได้หากไม่มีการอ้างอิงเพิ่มเติม

(2) อาร์กิวเมนต์ไปยัง someOperation อ้างถึงที่เก็บอ็อบเจ็กต์ข้อมูลต้นฉบับที่จัดเก็บซึ่งเป็นสำเนาของผลลัพธ์ของ (1) จะถูกคัดลอกอีกครั้งสำหรับเอ็นจินลงในคอนเทนเนอร์ zval ในขณะที่สิ่งนี้เกิดขึ้นล็อคการอ่านจะถูกเก็บไว้ ที่เก็บอ็อบเจ็กต์ล็อคจะถูกปล่อยออกมาและเครื่องยนต์สามารถเรียกใช้ฟังก์ชันได้ เมื่อสร้าง zval ขึ้นมาจะมีการอ้างอิงเป็น 0 ทำให้เอ็นจิ้นสามารถปลดปล่อยสำเนาได้เมื่อการดำเนินการเสร็จสิ้นเนื่องจากไม่มีการอ้างอิงอื่น ๆ

(3) อาร์กิวเมนต์สุดท้ายที่จะ preg_match อ้างอิงที่เก็บข้อมูลได้รับการล็อกการอ่านชุดข้อมูลใน (1) จะถูกคัดลอกไปยัง zval อีกครั้งโดยมีการอ้างอิงเป็น 0 ล็อกจะถูกปลดล็อกการเรียกใช้ preg_match ทำงานบน สำเนาข้อมูลนั่นคือสำเนาของข้อมูลต้นฉบับ

สิ่งที่ควรรู้:

  • ตารางแฮชของที่เก็บอ็อบเจ็กต์ที่จัดเก็บข้อมูลเธรดปลอดภัยจะ
    ขึ้นอยู่กับ TsHashTable ที่จัดส่งด้วย PHP โดย Zend

  • ที่เก็บอ็อบเจ็กต์มีล็อกการอ่านและเขียนมีการล็อกการเข้าถึงเพิ่มเติมสำหรับ TsHashTable เช่นนั้นหากต้องการ (และทำเช่นนี้ var_dump / print_r การเข้าถึงคุณสมบัติโดยตรงตามที่เอ็นจิ้น PHP ต้องการอ้างอิง) pthreads สามารถจัดการ TsHashTable ภายนอก API ที่กำหนด

  • การล็อคจะถูกล็อคไว้เฉพาะในขณะที่การคัดลอกเกิดขึ้นเมื่อทำสำเนาแล้วล็อคจะถูกคลายออกตามลำดับที่เหมาะสม

ซึ่งหมายความว่า:

  • เมื่อมีการเขียนเกิดขึ้นไม่เพียง แต่จะมีการล็อกการอ่านและการเขียนเท่านั้น แต่ยังมีการล็อกการเข้าถึงเพิ่มเติมอีกด้วย ตารางนั้นถูกปิดลงไม่มีทางเป็นไปได้ที่บริบทอื่นจะสามารถล็อกอ่านเขียนหรือส่งผลกระทบต่อตารางได้

  • เมื่อการอ่านเกิดขึ้นไม่เพียง แต่ล็อคการอ่านเท่านั้น แต่ยังมีการล็อกการเข้าถึงเพิ่มเติมอีกด้วยตารางจะถูกล็อคอีกครั้ง

ไม่มีสองบริบทที่สามารถเข้าถึงข้อมูลเดียวกันจากที่เก็บอ็อบเจ็กต์ได้ทั้งทางกายภาพและพร้อมกัน แต่การเขียนในบริบทใด ๆ ที่มีการอ้างอิงจะส่งผลต่อข้อมูลที่อ่านในบริบทใด ๆ ที่มีการอ้างอิง

นี่คือสถาปัตยกรรมที่ไม่ใช้ร่วมกันและวิธีเดียวที่จะมีอยู่ร่วมกัน ผู้ที่เข้าใจเล็กน้อยจะเห็นว่ามีการคัดลอกเกิดขึ้นมากมายที่นี่และพวกเขาจะสงสัยว่านั่นเป็นสิ่งที่ดีหรือไม่ การคัดลอกจำนวนมากเกิดขึ้นภายในรันไทม์แบบไดนามิกนั่นคือพลวัตของภาษาแบบไดนามิก pthreads ถูกนำไปใช้ที่ระดับของอ็อบเจ็กต์เนื่องจากสามารถรับการควบคุมที่ดีได้มากกว่าอ็อบเจ็กต์เดียว แต่เมธอด - โค้ดที่โปรแกรมเมอร์ดำเนินการ - มีบริบทอื่นโดยไม่ต้องล็อกและคัดลอก - ขอบเขตวิธีโลคัล ขอบเขตของวัตถุในกรณีของวัตถุ pthreads ควรได้รับการปฏิบัติเป็นวิธีการแบ่งปันข้อมูลระหว่างบริบทนั่นคือวัตถุประสงค์ ด้วยเหตุนี้คุณสามารถใช้เทคนิคเพื่อหลีกเลี่ยงการล็อกที่เก็บอ็อบเจ็กต์เว้นแต่จะจำเป็น

ไลบรารีและส่วนขยายส่วนใหญ่ที่มีให้สำหรับ PHP นั้นเป็นแบบบาง ๆ สำหรับบุคคลที่สามการทำงานหลักของ PHP ในระดับเดียวกันนั้นเป็นสิ่งเดียวกัน pthreads ไม่ใช่กระดาษห่อบาง ๆ รอบ ๆ Posix Threads; เป็นเธรด API ตาม Posix เธรด ไม่มีประเด็นใดในการใช้งาน Threads ใน PHP ที่ผู้ใช้ไม่เข้าใจหรือไม่สามารถใช้งานได้ ไม่มีเหตุผลที่คนที่ไม่รู้ว่า mutex คืออะไรหรือไม่ควรใช้ประโยชน์จากสิ่งที่พวกเขามีทั้งในแง่ของทักษะและทรัพยากร อ็อบเจ็กต์ทำหน้าที่เหมือนอ็อบเจกต์ แต่ที่ใดก็ตามที่สองบริบทจะชนกัน pthreads จะให้ความเสถียรและความปลอดภัย

ทุกคนที่เคยทำงานใน java จะเห็นความคล้ายคลึงกันระหว่างออบเจ็กต์ pthreads และเธรดใน java ไม่ต้องสงสัยเลยว่าคนกลุ่มเดียวกันเหล่านั้นจะเห็นข้อผิดพลาดที่เรียกว่า ConcurrentModificationException - เนื่องจากมันเกิดข้อผิดพลาดจากรันไทม์ java หากสองเธรดเขียนข้อมูลทางกายภาพเดียวกัน ควบคู่กันไป ฉันเข้าใจว่าเหตุใดจึงมีอยู่ แต่มันทำให้ฉันงงงวยว่าด้วยทรัพยากรที่มีราคาถูกเท่าที่มีประกอบกับความจริงที่ว่ารันไทม์สามารถตรวจจับการทำงานพร้อมกันในเวลาที่แน่นอนและมีเพียงเวลาเดียวที่ผู้ใช้จะสามารถบรรลุความปลอดภัยได้ โยนข้อผิดพลาดร้ายแรงที่รันไทม์แทนที่จะจัดการการดำเนินการและการเข้าถึงข้อมูล

pthreads จะไม่มีข้อผิดพลาดโง่ ๆ เกิดขึ้น API ถูกเขียนขึ้นเพื่อให้เธรดมีเสถียรภาพและเข้ากันได้มากที่สุดฉันเชื่อว่า

มัลติเธรดไม่เหมือนกับการใช้ฐานข้อมูลใหม่ควรให้ความสนใจอย่างใกล้ชิดกับทุกคำในคู่มือและตัวอย่างที่มาพร้อมกับ pthreads

สุดท้ายจากคู่มือ PHP:

pthreads เป็นและเป็นการทดลองที่ให้ผลลัพธ์ที่ดีทีเดียว ข้อ จำกัด หรือคุณสมบัติใด ๆ อาจเปลี่ยนแปลงได้ตลอดเวลา นั่นคือธรรมชาติของการทดลอง ข้อ จำกัด - มักกำหนดโดยการนำไปใช้ - มีอยู่ด้วยเหตุผลที่ดี จุดมุ่งหมายของ pthreads คือการจัดหาโซลูชันที่มีประโยชน์สำหรับการทำงานหลายอย่างใน PHP ในทุกระดับ ในสภาพแวดล้อมที่ pthread ดำเนินการข้อ จำกัด และข้อ จำกัด บางประการเป็นสิ่งจำเป็นเพื่อให้สภาพแวดล้อมมีเสถียรภาพ


14
เรื่องไร้สาระที่สุด.
Joe Watkins

7
@GeoC ฉันไม่แน่ใจด้วยซ้ำว่าจุดนี้ของคุณคืออะไรนั่นเป็นเพียงการพูดพล่อยๆและคุณไม่ได้ให้เหตุผลเหตุผลหรืออย่างอื่นว่าทำไมคุณถึงไม่เห็นด้วยกับข้อโต้แย้งใด ๆ (ซึ่งฉันไม่สามารถเห็นได้ในโพสต์) .
Jimbo

13
@Tudor ฉันไม่คิดว่าคุณรู้จริงๆว่าคุณกำลังพูดถึงอะไรดังนั้นฉันยินดีที่จะไม่สนใจคุณ
Joe Watkins

4
@Tudor - นักวิทยาศาสตร์หลายคนไม่ "เห็นประเด็น" ของสิ่งใหม่ในสาขาของตนหรือสิ่งที่มีประโยชน์ ประวัติศาสตร์ได้แสดงให้เห็นว่าบ่อยครั้งที่ผู้คนเช่นตัวคุณเองนั้นผิดพลาดมันเป็นเรื่องจริง เช่นเดียวกับความจริงที่ว่าทุกสิ่งที่คุณเขียนที่นี่คืออุจจาระโดยไม่มีคำพูดที่ดีกว่า ฉันขอแนะนำเป็นอย่างยิ่งโดยคำนึงถึงทุกสิ่งที่เป็นบวกอย่าเข้าร่วมในหัวข้อที่คุณไม่รู้อะไรเลย (สิ่งนี้เป็นเรื่องเดียว)
NB

12
เรื่องตลก Joe Watkins เป็นผู้เขียน pthreads และ Tudor ก็ยังพยายามพิสูจน์ว่าเขาคิดผิด
Hristo Valkanov

48

นี่คือตัวอย่างของสิ่งที่ Wilco แนะนำ:

$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);

โดยทั่วไปจะเรียกใช้สคริปต์ PHP ที่บรรทัดคำสั่ง แต่ส่งคืน PID ทันทีจากนั้นทำงานในพื้นหลัง (echo $! ช่วยให้มั่นใจได้ว่าจะไม่มีการส่งคืนอื่นใดนอกจาก PID) ซึ่งจะช่วยให้สคริปต์ PHP ของคุณดำเนินการต่อหรือออกหากคุณต้องการ เมื่อฉันใช้สิ่งนี้ฉันได้เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าอื่นโดยทุกๆ 5 ถึง 60 วินาทีจะมีการโทร AJAX เพื่อตรวจสอบว่ารายงานยังทำงานอยู่หรือไม่ (ฉันมีตารางสำหรับเก็บ gen_id และผู้ใช้ที่เกี่ยวข้อง) สคริปต์ตรวจสอบจะรันสิ่งต่อไปนี้:

exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
     // less than 2 rows in the ps, therefore report is complete
}

มีโพสต์สั้น ๆ เกี่ยวกับเทคนิคนี้ที่นี่: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/


ฉันมีปัญหาเล็กน้อยคุณจะตรวจสอบสถานะของกระบวนการเบื้องหลังได้อย่างไร? คุณช่วยสอนฉันได้ไหม
slier

25

กล่าวโดยย่อ: ใช่มีหลายเธรดใน php แต่คุณควรใช้การประมวลผลหลายขั้นตอนแทน

ข้อมูลเบื้องหลัง: เธรดเทียบกับกระบวนการ

มีความสับสนเล็กน้อยเกี่ยวกับความแตกต่างของเธรดและกระบวนการดังนั้นฉันจะอธิบายทั้งสองอย่างในไม่ช้า:

  • ด้ายเป็นลำดับของคำสั่งที่ CPU จะดำเนินการ ข้อมูลเดียวที่ประกอบด้วยตัวนับโปรแกรม คอร์ของ CPU แต่ละคอร์จะประมวลผลทีละเธรดเท่านั้น แต่สามารถสลับระหว่างการดำเนินการของเธรดที่แตกต่างกันได้ผ่านการตั้งเวลา
  • กระบวนการคือชุดของทรัพยากรที่ใช้ร่วมกัน นั่นหมายความว่าประกอบด้วยส่วนหนึ่งของหน่วยความจำตัวแปรอินสแตนซ์ออบเจ็กต์ที่จับไฟล์ mutexes การเชื่อมต่อฐานข้อมูลและอื่น ๆ แต่ละกระบวนการยังประกอบด้วยเธรดอย่างน้อยหนึ่งเธรด เธรดทั้งหมดของกระบวนการเดียวกันใช้ทรัพยากรร่วมกันดังนั้นคุณสามารถใช้ตัวแปรในเธรดหนึ่งที่คุณสร้างในอีกเธรดได้ หากเธรดเหล่านั้นเป็นส่วนหนึ่งของกระบวนการที่แตกต่างกันสองกระบวนการก็จะไม่สามารถเข้าถึงทรัพยากรของกันและกันได้โดยตรง ในกรณีนี้คุณต้องมีการสื่อสารระหว่างกระบวนการเช่นไปป์ไฟล์ซ็อกเก็ต ...

multiprocessing

คุณสามารถใช้คอมพิวเตอร์คู่ขนานได้โดยการสร้างกระบวนการใหม่ (ซึ่งมีเธรดใหม่ด้วย) ด้วย php หากเธรดของคุณไม่ต้องการการสื่อสารหรือการซิงโครไนซ์มากนักนี่เป็นทางเลือกของคุณเนื่องจากกระบวนการต่างๆแยกกันและไม่สามารถรบกวนการทำงานของกันและกันได้ แม้ว่าจะเกิดปัญหาขึ้น แต่ก็ไม่เกี่ยวข้องกับผู้อื่น หากคุณต้องการการสื่อสารมากคุณควรอ่านที่ "มัลติเธรด" หรือ - น่าเศร้า - ลองใช้ภาษาโปรแกรมอื่นเนื่องจากการสื่อสารและการซิงโครไนซ์ระหว่างกระบวนการทำให้เกิดผิวมากมาย

ใน php คุณมีสองวิธีในการสร้างกระบวนการใหม่:

ให้ OS ทำเพื่อคุณ : คุณสามารถบอกระบบปฏิบัติการของคุณให้สร้างกระบวนการใหม่และเรียกใช้สคริปต์ php ใหม่ (หรือเหมือนกัน) ในนั้น

  • สำหรับlinuxคุณสามารถใช้สิ่งต่อไปนี้หรือพิจารณาคำตอบของ Darryl Hein :

    $cmd = 'nice php script.php 2>&1 & echo $!';
    pclose(popen($cmd, 'r'));
    
  • สำหรับwindowsคุณสามารถใช้สิ่งนี้:

    $cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
    pclose(popen($cmd, 'r'));
    

ทำมันเองด้วยส้อม : PHP นอกจากนี้ยังมีความเป็นไปได้ที่จะใช้ฟอร์กผ่านฟังก์ชั่นpcntl_fork () คุณสามารถดูบทแนะนำที่ดีเกี่ยวกับวิธีการทำสิ่งนี้ได้ที่นี่แต่ฉันไม่แนะนำอย่างยิ่งที่จะไม่ใช้มันเนื่องจากส้อมเป็นอาชญากรรมต่อมนุษยชาติและโดยเฉพาะอย่างยิ่งต่ออุ๊บ

multithreading

ด้วยมัลติเธรดเธรดทั้งหมดของคุณจะแชร์ทรัพยากรเพื่อให้คุณสามารถสื่อสารระหว่างกันและซิงโครไนซ์ได้อย่างง่ายดายโดยไม่ต้องเสียค่าใช้จ่ายมากนัก ในอีกด้านหนึ่งคุณต้องรู้ว่าคุณกำลังทำอะไรอยู่เนื่องจากสภาพการแข่งขันและการหยุดชะงักนั้นสร้างได้ง่าย แต่แก้ไขจุดบกพร่องได้ยากมาก

PHP มาตรฐานไม่ได้ให้ multithreading ใด ๆ แต่มี (จากการทดลอง) ส่วนขยายที่จริงไม่ - pthreads เอกสาร API ของมันทำให้เป็นphp.netด้วยซ้ำ ด้วยวิธีนี้คุณสามารถทำบางสิ่งได้ตามที่คุณสามารถทำได้ในภาษาโปรแกรมจริง :-) ดังนี้:

class MyThread extends Thread {
    public function run(){
        //do something time consuming
    }
}

$t = new MyThread();
if($t->start()){
    while($t->isRunning()){
        echo ".";
        usleep(100);
    }
    $t->join();
}

สำหรับlinuxมีคู่มือการติดตั้งอยู่ที่นี่ที่ stackoverflow

สำหรับwindowsตอนนี้มี:

  • ก่อนอื่นคุณต้องมี php เวอร์ชันที่ปลอดภัย
  • คุณต้องมีเวอร์ชันที่รวบรวมไว้ล่วงหน้าของทั้ง pthreads และส่วนขยาย php พวกเขาสามารถดาวน์โหลดได้ที่นี่ ตรวจสอบให้แน่ใจว่าคุณดาวน์โหลดเวอร์ชันที่เข้ากันได้กับเวอร์ชัน php ของคุณ
  • คัดลอก php_pthreads.dll (จากไฟล์ zip ที่คุณเพิ่งดาวน์โหลด) ลงในโฟลเดอร์ส่วนขยาย php ของคุณ ([phpDirectory] / ext)
  • คัดลอก pthreadVC2.dll ไปยัง [phpDirectory] (โฟลเดอร์รูทไม่ใช่โฟลเดอร์ส่วนขยาย)
  • แก้ไข [phpDirectory] /php.ini และแทรกบรรทัดต่อไปนี้

    extension=php_pthreads.dll
  • ทดสอบกับสคริปต์ด้านบนด้วยการนอนหลับหรืออะไรบางอย่างที่มีความคิดเห็น

และตอนนี้มีขนาดใหญ่แต่ : แม้ว่างานนี้จริงๆ, PHP ไม่ได้ทำมาเพื่อ multithreading มี php รุ่นที่ปลอดภัยสำหรับเธรดและเมื่อถึง v5.4 ดูเหมือนว่าเกือบจะปราศจากข้อผิดพลาด แต่การใช้ php ในสภาพแวดล้อมแบบมัลติเธรดยังคงไม่แนะนำในคู่มือ php (แต่บางทีพวกเขาอาจไม่ได้อัปเดตคู่มือของพวกเขาใน นี้ยัง) ปัญหาที่ใหญ่กว่ามากอาจเป็นเพราะส่วนขยายทั่วไปจำนวนมากไม่ปลอดภัยต่อเธรด ดังนั้นคุณอาจได้รับเธรดที่มีส่วนขยาย php นี้ แต่ฟังก์ชั่นที่คุณใช้นั้นยังไม่ปลอดภัยต่อเธรดดังนั้นคุณอาจพบกับสภาพการแข่งขันการหยุดชะงักและอื่น ๆ ในโค้ดที่คุณไม่ได้เขียนเอง ...


5
นั่นผิดอย่างมากบทความที่คุณอ้างถึงมาจากปี 2008 หาก PHP ไม่เธรดปลอดภัยที่แกนหลักก็จะไม่มีโมดูล SAPI เธรด
Joe Watkins

1
@Joe: เอาล่ะฉันเปลี่ยนในแกนหลักแล้วปลอดภัยต่อเธรด แต่ส่วนขยายจำนวนมากไม่ได้
Francois Bourgeois

1
เยอะมั้ย? ฉันคิดว่าคุณจะพบว่ามีน้อยมากคุณพบเอกสาร แต่ไม่สามารถอ่านได้อย่างถูกต้องหมายเหตุ: สิ่งที่มีเครื่องหมาย * ไม่ใช่ไลบรารีที่ปลอดภัยต่อเธรดและไม่ควรใช้กับ PHP เป็นโมดูลเซิร์ฟเวอร์ใน multi - เซิร์ฟเวอร์เว็บ Windows แบบเธรด (IIS, Netscape) สิ่งนี้ไม่สำคัญในสภาพแวดล้อม Unix
Joe Watkins

6
PHP เป็นเธรดที่ปลอดภัยมากและเป็นเวลาหลายปีแล้วไลบรารีภายนอกบางแห่งและไลบรารีที่รวมอยู่สองสามแห่งนั้นไม่ได้มี แต่มีการบันทึกไว้อย่างดีและค่อนข้างชัดเจนอยู่ดี pthreads สร้างเธรดที่ปลอดภัยเท่ากับเธรดที่สร้างโดย zend ใน sapi แบบมัลติเธรดฉันรู้สิ่งนี้เพราะฉันคนเดียวเขียน pthreads มันใช้ API ที่มีอยู่ทั้งหมดที่ PHP เปิดเผยเช่นเดียวกับ API ของเซิร์ฟเวอร์ฉันไม่ได้บอกว่ามันเสถียรอย่างสมบูรณ์ แต่ภาพที่คุณวาดนั้นผิดธรรมดาและได้รับข้อมูลไม่ดีมาก
Joe Watkins

@Joe: เมื่อคู่มือบอกว่าสิ่งนี้ไม่สำคัญสำหรับสภาพแวดล้อม Unix พวกเขาอ้างถึงความจริงที่ว่าในระบบ Unix apache ใช้หลายกระบวนการและบน Windows จะใช้เธรด โดยพื้นฐานแล้วพวกเขาจะพูดว่า "ถ้าคุณไม่ได้ใช้เธรดคุณก็ไม่ต้องกังวลเกี่ยวกับส่วนขยายที่ไม่ปลอดภัยสำหรับเธรด" เมื่อเราใช้เธรดกับ pthreads แน่นอนว่ามันมีความสำคัญกับสภาพแวดล้อม Unix ด้วย
Francois Bourgeois

17

คุณสามารถใช้pcntl_fork ()เพื่อให้ได้สิ่งที่คล้ายกับเธรด ในทางเทคนิคแล้วมันเป็นกระบวนการที่แยกจากกันดังนั้นการสื่อสารระหว่างทั้งสองจึงไม่ง่ายอย่างกับเธรดและฉันเชื่อว่ามันจะไม่ทำงานหาก PHP ถูกเรียกโดย apache


4
ฉันประสบความสำเร็จในการใช้ pcntl_fork เพื่อขนานงานนำเข้าข้อมูลจำนวนมหาศาล ใช้งานได้ดีและฉันก็ใช้งานได้ในเวลาประมาณหนึ่งชั่วโมง มีช่วงการเรียนรู้เล็กน้อย แต่เมื่อคุณเข้าใจว่าเกิดอะไรขึ้นมันก็ค่อนข้างตรงไปตรงมา
Frank Farmer

แฟรงค์ใช้ CLI php หรือ apache PHP หรือเปล่า
Artem Russakovskii

@ Artem: ฉันก็อยากรู้เหมือนกัน
Josh K

5
@ แฟรงค์ฟาร์เมอร์กำลังแกล้งพวกเรา ... เหมือนกับแพ็กเกจ PECL
Roger

1
ฉันใช้ pcntl_fork กับ CLI ฉันไม่เคยลองใน apache; ฟังดูมีความเสี่ยง แม้แต่ใน CLI ก็ยังมีปัญหาที่ไม่คาดคิด ฉันดูเหมือนจะมีปัญหาที่ถ้าเด็กคนหนึ่งปิดที่จับฐานข้อมูล (เพราะมันทำงานเสร็จแล้ว) มันก็ปิดการเชื่อมต่อสำหรับพี่น้องด้วยเช่นกัน เนื่องจากเด็กเป็นสำเนาของผู้ปกครองควรเตรียมความพร้อมสำหรับความแปลกประหลาด ตั้งแต่นั้นมาฉันได้ออกแบบโค้ดของฉันใหม่เพื่อสร้างกระบวนการใหม่ที่แยกจากกันโดยสิ้นเชิงผ่าน exec () - มันจะสะอาดกว่าด้วยวิธีนี้
Frank Farmer


7

pcntl_fork()คือสิ่งที่คุณกำลังค้นหา แต่กระบวนการฟอร์กไม่ใช่เธรด ดังนั้นคุณจะมีปัญหาในการแลกเปลี่ยนข้อมูล เพื่อแก้ปัญหาเหล่านี้คุณสามารถใช้ฟังก์ชัน phps semaphore ( http://www.php.net/manual/de/ref.sem.php ) คิวข้อความอาจจะง่ายกว่าเล็กน้อยสำหรับการเริ่มต้นมากกว่าเซ็กเมนต์หน่วยความจำแบบแบ่งใช้

อย่างไรก็ตามกลยุทธ์ที่ฉันใช้ในเว็บเฟรมเวิร์กที่ฉันกำลังพัฒนาซึ่งโหลดบล็อกที่ใช้ทรัพยากรจำนวนมากของหน้าเว็บ (อาจมีการร้องขอจากภายนอก) แบบขนาน: ฉันกำลังทำคิวงานเพื่อให้ทราบว่าฉันกำลังรอข้อมูลอะไรอยู่จากนั้นฉันก็แยก ปิดงานสำหรับทุกกระบวนการ เมื่อเสร็จแล้วพวกเขาจะเก็บข้อมูลไว้ในแคช apc ภายใต้คีย์เฉพาะที่กระบวนการหลักสามารถเข้าถึงได้ ทุกครั้งที่มีข้อมูลจะดำเนินต่อไป ฉันใช้วิธีง่ายๆusleep()ในการรอเพราะการสื่อสารระหว่างกระบวนการไม่สามารถทำได้ใน apache (เด็ก ๆ จะขาดการเชื่อมต่อกับพ่อแม่และกลายเป็นซอมบี้ ... ) ดังนั้นสิ่งนี้จึงนำฉันไปสู่สิ่งสุดท้ายนั่นคือการฆ่าเด็กทุกคนด้วยตนเอง! มีคลาสเช่นกันที่แยกกระบวนการ แต่เก็บข้อมูลฉันไม่ได้ตรวจสอบ แต่ zend framework มีหนึ่งและพวกเขามักจะทำโค้ดช้า แต่เชื่อถือได้ คุณสามารถพบได้ที่นี่: http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html ฉันคิดว่าพวกเขาใช้กลุ่ม shm! สุดท้ายดี แต่ไม่ท้ายสุดมีข้อผิดพลาดในเว็บไซต์ zend นี้ข้อผิดพลาดเล็กน้อยในตัวอย่าง

while ($process1->isRunning() && $process2->isRunning()) {
    sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
    sleep(1);
}



5

ฉันมีคลาสเธรด PHP ที่ทำงานได้อย่างไม่มีที่ติในสภาพแวดล้อมการผลิตมานานกว่าสองปีแล้ว

แก้ไข: ตอนนี้พร้อมใช้งานแล้วในฐานะไลบรารีนักแต่งเพลงและเป็นส่วนหนึ่งของกรอบงาน MVC ของฉัน Hazaar MVC

ดู: https://git.hazaarlabs.com/hazaar/hazaar-thread


จะเกิดอะไรขึ้นถ้าทำตามตัวอย่างของคุณโปรแกรมใน file.php สมมติว่ามันเป็นปัญหามากกับการมีอยู่ของรายการ uris ของเว็บไซต์ 10k จากนั้นต้องบันทึกผลลัพธ์ในไฟล์ CSV ... ไฟล์นี้จะเขียนเป็น a ปัญหา?
Roger

กระบวนการย่อยจะรันในฐานะผู้ใช้เดียวกันกับเว็บเซิร์ฟเวอร์ / สคริปต์พาเรนต์ ดังนั้นเมื่อเขียนไฟล์คุณจะมีข้อควรพิจารณาเกี่ยวกับสิทธิ์เช่นเดียวกับที่คุณทำตามปกติ หากคุณมีปัญหาในการเขียนไฟล์ให้ลองเขียนถึง / tmp และเมื่อใช้งานได้แล้วให้ไปจากที่นั่น
Jamie Carl

1
ตอนนี้ลิงค์ตายไปแล้วเนื่องจากการออกแบบใหม่คุณสามารถหาได้จากเครื่องย้อนกลับที่นี่: web.archive.org/web/20130922043615/http://dev.funkynerd.com/…
Tony

เพิ่มไปยังเฟรมเวิร์ก MVC ของฉันตอนนี้ ดู: git.hazaarlabs.com/hazaar/hazaar-thread
Jamie Carl


1

เคยได้ยินเกี่ยวกับappserverจากแผนกเทคโนโลยีหรือไม่?

มันเขียนด้วย php และทำงานเป็นแอพเซิร์ฟเวอร์ที่จัดการมัลติเธรดสำหรับแอพพลิเคชั่น php ที่มีทราฟฟิกสูง ยังอยู่ในช่วงเบต้า แต่มีแนวโน้มดีมาก


-3

มีค่อนข้างชัดเจนและเร็ว ๆ นี้จะเลิกใช้คุณลักษณะที่เรียกว่าเป็นเห็บ สิ่งเดียวที่ฉันเคยใช้คืออนุญาตให้สคริปต์จับ SIGKILL (Ctrl + C) และปิดลงอย่างสง่างาม


3
เห็บไม่ทำงานแบบขนาน โดยพื้นฐานแล้วหลังจากทุกคำสั่งฟังก์ชันติ๊กของคุณจะทำงาน ในขณะที่ฟังก์ชันติ๊กของคุณกำลังทำงานอยู่รหัสหลักจะไม่ทำงาน
Frank Farmer

1
เห็บจำเป็นสำหรับตัวจัดการสัญญาณ () เท่านั้น
นิค
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.