ไลบรารีนี้มี wrapper ขนาดเล็กและใช้งานง่ายสำหรับส่วนขยาย PCNTL ของ PHP ช่วยให้สามารถรันกระบวนการต่างๆ พร้อมกันได้ด้วย API ที่ใช้งานง่าย
เราลงทุนทรัพยากรจำนวนมากเพื่อสร้างแพ็คเกจโอเพ่นซอร์สที่ดีที่สุดในระดับเดียวกัน คุณสามารถสนับสนุนเราได้โดยการซื้อหนึ่งในผลิตภัณฑ์ที่ต้องชำระเงินของเรา
เราขอขอบคุณอย่างยิ่งที่คุณส่งโปสการ์ดจากบ้านเกิดของคุณถึงเรา โดยระบุว่าคุณใช้แพ็คเกจใดของเรา คุณจะพบที่อยู่ของเราในหน้าติดต่อของเรา เราเผยแพร่โปสการ์ดที่ได้รับทั้งหมดบนวอลล์โปสการ์ดเสมือนของเรา
คุณสามารถติดตั้งแพ็คเกจผ่านทางผู้แต่ง:
composer require spatie/async
use Spatie Async Pool ;
$ pool = Pool:: create ();
foreach ( $ things as $ thing ) {
$ pool -> add ( function () use ( $ thing ) {
/ / Do a thing
})-> then ( function ( $ output ) {
/ / Handle success
})-> catch ( function ( Throwable $ exception ) {
/ / Handle exception
});
}
$ pool -> wait ();
เมื่อสร้างกระบวนการแบบอะซิงโครนัส คุณจะได้รับอินสแตนซ์ของ ParallelProcess
ที่ส่งคืน คุณสามารถเพิ่ม hooks เหตุการณ์ต่อไปนี้ในกระบวนการได้
$ pool
-> add ( function () {
/ / ...
})
-> then ( function ( $ output ) {
/ / On success , `$output` is returned by the process or callable you passed to the queue .
})
-> catch ( function ( $ exception ) {
/ / When an exception is thrown from within a process , it 's caught and passed here.
})
-> timeout ( function () {
/ / A process took too long to finish.
})
;
แทนที่จะใช้วิธีการกับอ็อบเจ็กต์ $pool
คุณอาจใช้ฟังก์ชัน async
และ await
helper ได้
use Spatie Async Pool ;
$ pool = Pool:: create ();
foreach ( range ( 1 , 5 ) as $ i ) {
$ pool [] = async ( function () {
usleep ( random_int ( 10 , 1000 ));
return 2 ;
})-> then ( function ( int $ output ) {
$ this -> counter += $ output ;
});
}
await ( $ pool );
หากมี Exception
หรือ Error
ถูกส่งออกมาจากภายในกระบวนการย่อย จะสามารถตรวจจับได้ต่อกระบวนการโดยการระบุการโทรกลับในวิธีการ ->catch()
$ pool
-> add ( function () {
/ / ...
})
-> catch ( function ( $ exception ) {
/ / Handle the thrown exception for this child process.
})
;
หากไม่มีการเพิ่มตัวจัดการข้อผิดพลาด ข้อผิดพลาดจะเกิดขึ้นในกระบวนการหลักเมื่อเรียก await()
หรือ $pool->wait()
หากกระบวนการลูกหยุดโดยไม่คาดคิดโดยไม่โยน Throwable
เอาต์พุตที่เขียนไปยัง stderr
จะถูกห่อและส่งเป็น SpatieAsyncParallelError
ในกระบวนการหลัก
ตามประเภทที่บ่งบอกถึงฟังก์ชัน catch
คุณสามารถจัดเตรียมตัวจัดการข้อผิดพลาดได้หลายตัว โดยแต่ละประเภทสำหรับข้อผิดพลาดแต่ละประเภท
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / Handle `MyException`
})
-> catch ( function ( OtherException $ e ) {
/ / Handle `OtherException`
});
โปรดทราบว่าทันทีที่มีการจัดการข้อยกเว้น มันจะไม่ทริกเกอร์ตัวจัดการอื่นๆ
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / This one is triggerd when `MyException` is thrown
})
-> catch ( function ( Exception $ e ) {
/ / This one is not triggerd , even though `M yException ` extends `E xception `
});
หากคุณต้องการหยุดพูลก่อนกำหนด เนื่องจากงานที่กำลังดำเนินการอยู่เสร็จสิ้นโดยกระบวนการลูกอย่างใดอย่างหนึ่ง คุณสามารถใช้เมธอด $pool->stop()
ได้ ซึ่งจะป้องกันไม่ให้พูลเริ่มกระบวนการเพิ่มเติมใดๆ
use Spatie Async Pool ;
$ pool = Pool:: create ();
/ / Generate 10 k processes generating random numbers
for ( $ i = 0 ; $ i < 10000 ; $ i ++) {
$ pool -> add ( function () use ( $ i ) {
return rand ( 0 , 100 );
})-> then ( function ( $ output ) use ( $ pool ) {
/ / If one of them randomly picks 100 , end the pool early .
if ( $ output === 100 ) {
$ pool -> stop ();
}
});
}
$ pool -> wait ();
โปรดทราบว่าพูลจะแสดงผลไร้ประโยชน์หลังจากหยุดทำงาน และควรสร้างพูลใหม่หากจำเป็น
ตามค่าเริ่มต้นพูลจะใช้ php
เพื่อดำเนินการกระบวนการย่อย คุณสามารถกำหนดค่าไบนารี่อื่นได้ดังนี้:
Pool:: create ()
-> withBinary ( ' /path/to/php ' );
นอกจากการใช้การปิดแล้ว คุณยังสามารถทำงานกับ Task
ได้อีกด้วย Task
มีประโยชน์ในสถานการณ์ที่คุณต้องการงานการตั้งค่าเพิ่มเติมในกระบวนการลูก เนื่องจากกระบวนการย่อยมักจะถูกบู๊ตจากไม่มีอะไรเลย จึงมีความเป็นไปได้ที่คุณจะต้องการเริ่มต้น เช่น คอนเทนเนอร์การพึ่งพาก่อนที่จะดำเนินการงาน คลาส Task
ช่วยให้ทำสิ่งนี้ได้ง่ายขึ้น
use Spatie Async Task ;
class MyTask extends Task
{
public function configure ()
{
/ / Setup eg . dependency container , load config , ...
}
public function run ()
{
/ / Do the real work here.
}
}
/ / Add the task to the pool
$ pool -> add ( new MyTask ());
หากคุณต้องการสรุปตรรกะของงานของคุณ แต่ไม่ต้องการสร้างออบเจ็กต์ Task
ที่สมบูรณ์ คุณอาจส่งผ่านออบเจ็กต์ที่เรียกใช้ได้ไปยัง Pool
class InvokableClass
{
/ / ...
public function __invoke ()
{
/ / ...
}
}
$ pool -> add ( new InvokableClass ( / * ... * / ));
คุณมีอิสระที่จะสร้างพูลได้มากเท่าที่คุณต้องการ แต่ละพูลมีคิวกระบวนการที่จะจัดการเป็นของตัวเอง
นักพัฒนาสามารถกำหนดค่าพูลได้:
use Spatie Async Pool ;
$ pool = Pool:: create ()
/ / The maximum amount of processes which can run simultaneously.
-> concurrency ( 20 )
/ / The maximum amount of time a process may take to finish in seconds
/ / ( decimal places are supported for more granular timeouts ) .
-> timeout ( 15 )
/ / Configure which autoloader sub processes should use.
-> autoload ( __DIR__ . ' /../../vendor/autoload.php ' )
/ / Configure how long the loop should sleep before re - checking the process statuses in microseconds .
-> sleepTime ( 50000 )
;
หากไม่ได้ติดตั้งส่วนขยายที่จำเป็น ( pcntl
และ posix
) ในรันไทม์ PHP ปัจจุบันของคุณ Pool
จะถอยกลับไปทำงานแบบซิงโครนัสโดยอัตโนมัติ
คลาส Pool
มีเมธอดแบบสแตติก isSupported
คุณสามารถเรียกใช้เพื่อตรวจสอบว่าแพลตฟอร์มของคุณสามารถรันกระบวนการแบบอะซิงโครนัสได้หรือไม่
หากคุณกำลังใช้ Task
เพื่อเรียกใช้กระบวนการ เฉพาะวิธี run
ของงานเหล่านั้นเท่านั้นที่จะถูกเรียกเมื่อทำงานในโหมดซิงโครนัส
เมื่อใช้แพ็คเกจนี้ คุณอาจสงสัยว่าเกิดอะไรขึ้นใต้พื้นผิว
เรากำลังใช้ส่วนประกอบ symfony/process
เพื่อสร้างและจัดการกระบวนการลูกใน PHP ด้วยการสร้างกระบวนการลูกได้ทันที เราสามารถรันสคริปต์ PHP พร้อมกันได้ ความขนานนี้สามารถปรับปรุงประสิทธิภาพได้อย่างมากเมื่อต้องรับมือกับงานซิงโครนัสหลายงาน ซึ่งไม่จำเป็นต้องรอซึ่งกันและกันจริงๆ ด้วยการให้งานเหล่านี้มีกระบวนการแยกต่างหากในการทำงาน ระบบปฏิบัติการพื้นฐานจึงสามารถดูแลการรันงานเหล่านั้นไปพร้อมกันได้
มีข้อแม้เมื่อกระบวนการวางไข่แบบไดนามิก: คุณต้องตรวจสอบให้แน่ใจว่าจะไม่มีกระบวนการมากเกินไปในคราวเดียว ไม่เช่นนั้นแอปพลิเคชันอาจขัดข้อง คลาส Pool
ที่จัดทำโดยแพ็คเกจนี้จะดูแลการจัดการกระบวนการได้มากเท่าที่คุณต้องการโดยการกำหนดเวลาและรันกระบวนการเหล่านั้นเมื่อเป็นไปได้
นั่นคือส่วนที่ async()
หรือ $pool->add()
ทำ ตอนนี้เรามาดูกันว่า await()
หรือ $pool->wait()
ทำอะไรได้บ้าง
เมื่อมีการสร้างกระบวนการหลายกระบวนการ แต่ละกระบวนการจะมีเวลาในการทำให้เสร็จสิ้นแยกกัน กระบวนการหนึ่งอาจเช่น ต้องรอการเรียก HTTP ในขณะที่อีกเครื่องต้องประมวลผลข้อมูลจำนวนมาก บางครั้งคุณมีคะแนนในโค้ดของคุณซึ่งต้องรอจนกว่าผลลัพธ์ของกระบวนการจะถูกส่งกลับ
นี่คือเหตุผลที่เราต้องรอ ณ จุดใดจุดหนึ่ง: เพื่อให้กระบวนการทั้งหมดในพูลเสร็จสิ้น ดังนั้นเราจึงมั่นใจได้ว่าจะปลอดภัยที่จะดำเนินการต่อโดยไม่ตั้งใจฆ่ากระบวนการย่อยที่ยังไม่เสร็จสิ้นโดยไม่ได้ตั้งใจ
การรอกระบวนการทั้งหมดเสร็จสิ้นโดยใช้การวนซ้ำ while
ซึ่งจะรอจนกว่ากระบวนการทั้งหมดจะเสร็จสิ้น การพิจารณาว่ากระบวนการเสร็จสิ้นเมื่อใดเสร็จสิ้นโดยใช้ Listener บนสัญญาณ SIGCHLD
สัญญาณนี้จะถูกส่งออกมาเมื่อกระบวนการลูกเสร็จสิ้นโดยเคอร์เนลระบบปฏิบัติการ ใน PHP 7.1 มีการรองรับการฟังและการจัดการสัญญาณที่ดีกว่ามาก ทำให้แนวทางนี้มีประสิทธิภาพมากกว่าเช่น การใช้ส้อมกระบวนการหรือซ็อกเก็ตในการสื่อสาร คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่นี่
เมื่อกระบวนการเสร็จสิ้น เหตุการณ์ความสำเร็จจะถูกทริกเกอร์ ซึ่งคุณสามารถเชื่อมต่อด้วยฟังก์ชัน ->then()
ในทำนองเดียวกัน เมื่อกระบวนการล้มเหลวหรือหมดเวลา ลูปจะอัปเดตสถานะของกระบวนการนั้นและเดินหน้าต่อไป เมื่อกระบวนการทั้งหมดเสร็จสิ้น ลูป while จะเห็นว่าไม่มีอะไรต้องรออีกต่อไปแล้วจึงหยุด นี่คือช่วงเวลาที่กระบวนการหลักของคุณสามารถดำเนินการต่อไปได้
เราได้เขียนบล็อกโพสต์ที่มีข้อมูลเพิ่มเติมเกี่ยวกับกรณีการใช้งานสำหรับแพ็คเกจนี้ ตลอดจนทำการเปรียบเทียบกับไลบรารี PHP แบบอะซิงโครนัสอื่นๆ เช่น ReactPHP และ Amp: http://stitcher.io/blog/asynchronous-php
composer test
โปรดดู CHANGELOG สำหรับข้อมูลเพิ่มเติมว่ามีอะไรเปลี่ยนแปลงเมื่อเร็วๆ นี้
โปรดดูการมีส่วนร่วมเพื่อดูรายละเอียด
หากคุณพบข้อบกพร่องเกี่ยวกับการรักษาความปลอดภัย โปรดส่งอีเมลมาที่ [email protected] แทนการใช้ตัวติดตามปัญหา
คุณสามารถใช้แพ็คเกจนี้ได้อย่างอิสระ แต่หากมันเหมาะกับสภาพแวดล้อมการใช้งานจริงของคุณ เราขอขอบคุณอย่างยิ่งที่คุณส่งโปสการ์ดจากบ้านเกิดของคุณมาให้เรา โดยระบุว่าคุณกำลังใช้แพ็คเกจใดของเรา
ที่อยู่ของเราคือ: Spatie, Kruikstraat 22, 2018 แอนต์เวิร์ป, เบลเยียม
เราเผยแพร่ไปรษณียบัตรที่ได้รับทั้งหมดบนเว็บไซต์ของบริษัทของเรา
ใบอนุญาตเอ็มไอที (MIT) โปรดดูไฟล์ใบอนุญาตสำหรับข้อมูลเพิ่มเติม