เรียกใช้งาน PHP แบบอะซิงโครนัส


144

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

จนถึงตอนนี้ในบางแห่งฉันใช้สิ่งที่รู้สึกเหมือนแฮ็คกับ exec () โดยทั่วไปการทำสิ่งต่าง ๆ เช่น:

exec("doTask.php $arg1 $arg2 $arg3 >/dev/null 2>&1 &");

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

ฉันกำลังคิดค้นวงล้ออีกครั้งหรือไม่? มีวิธีแก้ปัญหาที่ดีกว่าแฮ็ค exec () หรือคิว MySQL หรือไม่?

คำตอบ:


80

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

การกลิ้งตัวคุณเองนั้นไม่ยุ่งยากเกินไปนี่คือตัวเลือกอื่น ๆ ที่คุณควรลอง:

  • GearMan - คำตอบนี้ถูกเขียนขึ้นในปี 2009 และตั้งแต่นั้น GearMan ดูตัวเลือกยอดนิยมดูความคิดเห็นด้านล่าง
  • ActiveMQถ้าคุณต้องการคิวข้อความโอเพนซอร์สแบบเต็มเป่า
  • ZeroMQ - นี่คือซ็อกเก็ตไลบรารีที่น่าสนใจซึ่งทำให้เขียนโค้ดแบบกระจายได้ง่ายโดยไม่ต้องกังวลเกี่ยวกับการเขียนโปรแกรมซ็อกเก็ตมากเกินไป คุณสามารถใช้มันสำหรับการจัดคิวข้อความบนโฮสต์เดียว - คุณเพียงแค่ให้ webapp ของคุณส่งบางสิ่งไปยังคิวที่แอปคอนโซลทำงานอย่างต่อเนื่องจะใช้งานในโอกาสที่เหมาะสมต่อไป
  • beanstalkd - พบเพียงคำเดียวในขณะที่เขียนคำตอบนี้ แต่ดูน่าสนใจ
  • droprเป็นโครงการคิวข้อความที่ใช้ PHP แต่ยังไม่ได้รับการดูแลตั้งแต่เดือนกันยายน 2010
  • php-enqueueเป็น wrapper ที่ได้รับการดูแลรักษาเมื่อเร็ว ๆ นี้ (2017) รอบ ๆ ระบบคิวที่หลากหลาย
  • ในที่สุดบล็อกโพสต์เกี่ยวกับการใช้memcached สำหรับการจัดคิวข้อความ

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


ขอบคุณสำหรับเคล็ดลับทั้งหมด ประเด็นที่เฉพาะเจาะจงเกี่ยวกับ ign_user_abort ไม่ได้ช่วยในกรณีของฉันจริง ๆ เป้าหมายของฉันคือการหลีกเลี่ยงความล่าช้าที่ไม่จำเป็นสำหรับผู้ใช้
davr

2
หากคุณตั้งค่าส่วนหัว HTTP ความยาวเนื้อหาในการตอบสนอง "ขอบคุณสำหรับการลงทะเบียน" เบราว์เซอร์ควรปิดการเชื่อมต่อหลังจากได้รับจำนวนไบต์ที่ระบุ สิ่งนี้ทำให้กระบวนการด้านเซิร์ฟเวอร์ทำงานอยู่ (สมมติว่ามีการตั้งค่า ign_user_abort) โดยไม่ทำให้ผู้ใช้ปลายทางรอ แน่นอนว่าคุณจะต้องคำนวณขนาดของเนื้อหาการตอบกลับของคุณก่อนที่จะเรนเดอร์ส่วนหัว แต่นั่นค่อนข้างง่ายสำหรับการตอบกลับสั้น ๆ
ปีเตอร์

1
Gearman ( gearman.org ) เป็นคิวข้อความโอเพนซอร์สที่ยอดเยี่ยมซึ่งเป็นแพลตฟอร์มข้าม คุณสามารถเขียนคนงานใน C, PHP, Perl หรือภาษาอื่นใดก็ได้ มีปลั๊กอิน Gearman UDF สำหรับ MySQL และคุณยังสามารถใช้ Net_Gearman จาก PHP หรือไคลเอ็นต์เกียร์แมนแพร์
Justin Swanhart

Gearman จะเป็นสิ่งที่ฉันอยากจะแนะนำในวันนี้ (ในปี 2015) ผ่านระบบจัดคิวงานที่กำหนดเองใด ๆ
ปีเตอร์

อีกทางเลือกหนึ่งคือการตั้งค่าเซิร์ฟเวอร์โหนด js เพื่อจัดการการร้องขอและส่งกลับการตอบสนองอย่างรวดเร็วกับงาน หลายสิ่งภายในสคริปต์โหนด js ถูกเรียกใช้แบบอะซิงโครนัสเช่นคำร้องขอ http
Zordon

22

เมื่อคุณต้องการที่จะดำเนินการคำขอ HTTP หนึ่งหรือหลายโดยไม่ต้องรอการตอบสนองก็มีโซลูชั่น PHP ที่เรียบง่ายเช่นกัน

ในสคริปต์การโทร:

$socketcon = fsockopen($host, 80, $errno, $errstr, 10);
if($socketcon) {   
   $socketdata = "GET $remote_house/script.php?parameters=... HTTP 1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";      
   fwrite($socketcon, $socketdata); 
   fclose($socketcon);
}
// repeat this with different parameters as often as you like

ใน script.php ที่เรียกว่าคุณสามารถเรียกใช้ฟังก์ชัน PHP เหล่านี้ในบรรทัดแรก:

ignore_user_abort(true);
set_time_limit(0);

สิ่งนี้ทำให้สคริปต์ทำงานต่อโดยไม่ จำกัด เวลาเมื่อปิดการเชื่อมต่อ HTTP


set_time_limit จะไม่มีผลหาก php ทำงานในเซฟโหมด
Baptiste Pernet

17

อีกวิธีหนึ่งในการแยกกระบวนการคือผ่านทาง curl คุณสามารถตั้งค่างานภายในของคุณเป็นเว็บเซอร์ ตัวอย่างเช่น:

จากนั้นในสคริปต์ที่ผู้ใช้เข้าถึงของคุณโทรไปยังบริการ:

$service->addTask('t1', $data); // post data to URL via curl

บริการของคุณสามารถติดตามคิวของงานด้วย mysql หรืออะไรก็ได้ที่คุณต้องการ: มันรวมอยู่ในบริการและสคริปต์ของคุณก็แค่ใช้ URL สิ่งนี้จะทำให้คุณพร้อมที่จะย้ายบริการไปยังเครื่อง / เซิร์ฟเวอร์อื่นหากจำเป็น (เช่นปรับขนาดได้ง่าย)

การเพิ่มการให้สิทธิ์ http หรือรูปแบบการให้สิทธิ์ที่กำหนดเอง (เช่นบริการเว็บของ Amazon) ช่วยให้คุณสามารถเปิดงานของคุณที่คน / บริการอื่น ๆ (ถ้าคุณต้องการ) และคุณสามารถดำเนินการต่อไปและเพิ่มบริการตรวจสอบด้านบนเพื่อติดตาม คิวและสถานะงาน

ใช้เวลาตั้งค่าเล็กน้อย แต่มีประโยชน์มากมาย


1
ฉันไม่ชอบวิธีการนี้เพราะเว็บเซิร์ฟเวอร์ทำงานหนักเกินไป
Oved Yavine

7

ฉันใช้Beanstalkdสำหรับโครงการหนึ่งและวางแผนที่จะอีกครั้ง ฉันพบว่ามันเป็นวิธีที่ยอดเยี่ยมในการรันกระบวนการแบบอะซิงโครนัส

สองสิ่งที่ฉันได้ทำไปแล้วคือ:

  • การปรับขนาดภาพ - และด้วยคิวที่โหลดเบา ๆ ส่งผ่านไปยังสคริปต์ PHP ที่ใช้ CLI การปรับขนาดรูปภาพขนาดใหญ่ (2mb +) ทำงานได้ดี แต่การพยายามปรับขนาดรูปภาพเดียวกันภายในอินสแตนซ์ mod_php นั้นทำงานเป็นประจำในพื้นที่หน่วยความจำ จำกัด กระบวนการ PHP ที่ 32MB และการปรับขนาดใช้เวลามากกว่านั้น)
  • การตรวจสอบในอนาคตอันใกล้ - beanstalkd มีความล่าช้า (ให้งานนี้ทำงานหลังจาก X วินาที) - ดังนั้นฉันจึงสามารถปิดการตรวจสอบเหตุการณ์ 5 หรือ 10 ครั้งในเวลาต่อมา

ผมเขียนตามระบบ Zend กรอบการถอดรหัส 'ดี' URL QueueTask('/image/resize/filename/example.jpg')ดังนั้นสำหรับตัวอย่างเช่นในการปรับขนาดภาพมันจะเรียก URL จะถูกถอดรหัสเป็นอาร์เรย์ครั้งแรก (โมดูลตัวควบคุมการกระทำพารามิเตอร์) จากนั้นแปลงเป็น JSON เพื่อฉีดไปยังคิวตัวเอง

สคริปต์ cli ที่ใช้เวลานานจากนั้นรับงานจากคิวเรียกใช้งาน (ผ่าน Zend_Router_Simple) และหากจำเป็นให้ใส่ข้อมูลลงใน memcached สำหรับเว็บไซต์ PHP เพื่อรับตามที่ต้องการเมื่อเสร็จสิ้น

หนึ่งรอยย่นที่ฉันใส่ไว้ก็คือ cli-script วิ่งไป 50 ลูปเท่านั้นก่อนที่จะรีสตาร์ท แต่ถ้ามันต้องการรีสตาร์ทตามที่วางแผนไว้มันจะทำทันที (ถูกเรียกใช้ผ่าน bash-script) หากมีปัญหาและฉันได้exit(0)(ค่าเริ่มต้นสำหรับexit;หรือdie();) มันจะหยุดก่อนสองสามวินาที


ฉันชอบรูปลักษณ์ของฝักถั่วเมื่อพวกเขาเพิ่มความคงทนฉันคิดว่ามันจะสมบูรณ์แบบ
davr

มีอยู่แล้วใน codebase และมีความเสถียร ฉันยังตั้งตาคอยที่จะตั้งชื่อ 'งาน' เพื่อให้ฉันสามารถโยนสิ่งต่าง ๆ ในนั้น แต่รู้ว่ามันจะไม่ถูกเพิ่มถ้ามีอยู่แล้วที่นั่น ดีสำหรับเหตุการณ์ปกติ
Alister Bulman

@AlisterBulman คุณสามารถให้ข้อมูลเพิ่มเติมหรือตัวอย่างสำหรับ "สคริปต์ cli ที่ใช้งานมานานแล้วเลือกงานจากคิว" ฉันพยายามสร้างสคริปต์ cli สำหรับแอปพลิเคชันของฉัน
Sasi varna kumar

7

หากเป็นเพียงคำถามของการจัดหางานที่มีราคาแพงในกรณีที่รองรับ php-fpm ทำไมไม่ใช้fastcgi_finish_request()ฟังก์ชั่น?

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

คุณไม่ได้ใช้ asynchronicity ในลักษณะนี้:

  1. ทำรหัสหลักทั้งหมดของคุณก่อน
  2. fastcgi_finish_request()ปฏิบัติ
  3. ทำสิ่งที่หนักทั้งหมด

จำเป็นต้องใช้ php-fpm อีกครั้ง


5

นี่คือคลาสที่เรียบง่ายที่ฉันเขียนโปรแกรมประยุกต์บนเว็บของฉัน จะช่วยให้การฟอร์กสคริปต์ PHP และสคริปต์อื่น ๆ ทำงานบน UNIX และ Windows

class BackgroundProcess {
    static function open($exec, $cwd = null) {
        if (!is_string($cwd)) {
            $cwd = @getcwd();
        }

        @chdir($cwd);

        if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
            $WshShell = new COM("WScript.Shell");
            $WshShell->CurrentDirectory = str_replace('/', '\\', $cwd);
            $WshShell->Run($exec, 0, false);
        } else {
            exec($exec . " > /dev/null 2>&1 &");
        }
    }

    static function fork($phpScript, $phpExec = null) {
        $cwd = dirname($phpScript);

        @putenv("PHP_FORCECLI=true");

        if (!is_string($phpExec) || !file_exists($phpExec)) {
            if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
                $phpExec = str_replace('/', '\\', dirname(ini_get('extension_dir'))) . '\php.exe';

                if (@file_exists($phpExec)) {
                    BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
                }
            } else {
                $phpExec = exec("which php-cli");

                if ($phpExec[0] != '/') {
                    $phpExec = exec("which php");
                }

                if ($phpExec[0] == '/') {
                    BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
                }
            }
        } else {
            if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
                $phpExec = str_replace('/', '\\', $phpExec);
            }

            BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
        }
    }
}

4

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

ฉันได้เพิ่มระดับพิเศษหนึ่งระดับไปแล้วและนั่นคือการรับและการจัดเก็บรหัสกระบวนการ สิ่งนี้ทำให้ฉันสามารถเปลี่ยนเส้นทางไปยังหน้าอื่นและให้ผู้ใช้นั่งบนหน้านั้นโดยใช้ AJAX เพื่อตรวจสอบว่ากระบวนการเสร็จสมบูรณ์แล้วหรือไม่ (ไม่มีรหัสกระบวนการอีกต่อไป) สิ่งนี้มีประโยชน์สำหรับกรณีที่ความยาวของสคริปต์จะทำให้เบราว์เซอร์หมดเวลา แต่ผู้ใช้ต้องรอให้สคริปต์นั้นดำเนินการให้เสร็จสิ้นก่อนขั้นตอนถัดไป (ในกรณีของฉันมันกำลังประมวลผลไฟล์ ZIP ขนาดใหญ่ที่มี CSV เช่นไฟล์ที่เพิ่มระเบียนได้ถึง 30,000 รายการในฐานข้อมูลหลังจากที่ผู้ใช้ต้องการยืนยันข้อมูลบางส่วน)

ฉันยังใช้กระบวนการที่คล้ายกันสำหรับการสร้างรายงาน ฉันไม่แน่ใจว่าฉันใช้ "การประมวลผลเบื้องหลัง" สำหรับบางอย่างเช่นอีเมลเว้นแต่จะมีปัญหาจริงกับ SMTP ช้า แต่ฉันอาจใช้ตารางเป็นคิวแล้วมีกระบวนการที่ทำงานทุกนาทีเพื่อส่งอีเมลภายในคิว คุณจะต้องระมัดระวังในการส่งอีเมลสองครั้งหรือปัญหาอื่นที่คล้ายคลึงกัน ฉันจะพิจารณากระบวนการจัดคิวที่คล้ายกันสำหรับงานอื่นเช่นกัน


1
คุณหมายถึงวิธีใดในประโยคแรกของคุณ
Simon East


2

เป็นความคิดที่ดีที่จะใช้ cURL ตามคำแนะนำของ rojoca

นี่คือตัวอย่าง คุณสามารถตรวจสอบ text.txt ในขณะที่สคริปต์ทำงานในพื้นหลัง:

<?php

function doCurl($begin)
{
    echo "Do curl<br />\n";
    $url = 'http://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
    $url = preg_replace('/\?.*/', '', $url);
    $url .= '?begin='.$begin;
    echo 'URL: '.$url.'<br>';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    echo 'Result: '.$result.'<br>';
    curl_close($ch);
}


if (empty($_GET['begin'])) {
    doCurl(1);
}
else {
    while (ob_get_level())
        ob_end_clean();
    header('Connection: close');
    ignore_user_abort();
    ob_start();
    echo 'Connection Closed';
    $size = ob_get_length();
    header("Content-Length: $size");
    ob_end_flush();
    flush();

    $begin = $_GET['begin'];
    $fp = fopen("text.txt", "w");
    fprintf($fp, "begin: %d\n", $begin);
    for ($i = 0; $i < 15; $i++) {
        sleep(1);
        fprintf($fp, "i: %d\n", $i);
    }
    fclose($fp);
    if ($begin < 10)
        doCurl($begin + 1);
}

?>

2
มันจะช่วยได้จริงๆถ้าซอร์สโค้ดจะถูกคอมเม้นท์ ฉันไม่รู้ว่าเกิดอะไรขึ้นในนั้นและส่วนใดเป็นตัวอย่างและส่วนใดที่สามารถใช้งานได้อีกครั้งเพื่อจุดประสงค์ของฉัน
Thomas Tempelmann

1

น่าเสียดายที่ PHP ไม่มีความสามารถในการทำเกลียวแบบดั้งเดิม ดังนั้นฉันคิดว่าในกรณีนี้คุณไม่มีทางเลือกนอกจากใช้รหัสที่กำหนดเองเพื่อทำสิ่งที่คุณต้องการ

หากคุณค้นหาข้อมูลเกี่ยวกับการทำเกลียว PHP บนอินเทอร์เน็ตบางคนคิดหาวิธีจำลองเธรดบน PHP


1

หากคุณตั้งค่าส่วนหัว HTTP ความยาวเนื้อหาในการตอบสนอง "ขอบคุณสำหรับการลงทะเบียน" เบราว์เซอร์ควรปิดการเชื่อมต่อหลังจากได้รับจำนวนไบต์ที่ระบุ สิ่งนี้ทำให้กระบวนการด้านเซิร์ฟเวอร์ทำงานอยู่ (สมมติว่ามีการตั้งค่า ign_user_abort) เพื่อให้สามารถทำงานได้โดยไม่ต้องรอผู้ใช้

แน่นอนคุณจะต้องคำนวณขนาดของเนื้อหาการตอบสนองของคุณก่อนที่จะเรนเดอร์ส่วนหัว แต่มันค่อนข้างง่ายสำหรับการตอบกลับสั้น ๆ (เขียนเอาต์พุตไปยังสตริง call strlen (), header header (), สตริงการแสดงผล)

วิธีนี้มีข้อดีที่จะไม่บังคับให้คุณจัดการคิว "front end" และแม้ว่าคุณอาจต้องทำงานบางอย่างใน back end เพื่อป้องกันไม่ให้กระบวนการลูก HTTP HTTP แข่งกันเหยียบย่ำนั่นเป็นสิ่งที่คุณต้องทำแล้ว , อย่างไรก็ตาม.


ดูเหมือนจะใช้งานไม่ได้ เมื่อฉันใช้header('Content-Length: 3'); echo '1234'; sleep(5);แม้ว่าเบราว์เซอร์จะใช้เวลาเพียง 3 ตัวอักษร แต่ก็ยังคงรอเป็นเวลา 5 วินาทีก่อนที่จะแสดงการตอบสนอง ฉันพลาดอะไรไป
Thomas Tempelmann

@ThomasTempelmann - คุณอาจต้องเรียก flush () เพื่อบังคับให้แสดงผลจริงทันทีมิฉะนั้นเอาต์พุตจะถูกบัฟเฟอร์จนกว่าสคริปต์ของคุณจะออกหรือมีข้อมูลเพียงพอที่จะส่งไปยัง STDOUT เพื่อล้างบัฟเฟอร์
ปีเตอร์

ฉันลองล้างหลายวิธีแล้วพบที่นี่ใน SO ไม่มีความช่วยเหลือ และข้อมูลดูเหมือนว่าจะไม่ได้รับการบีบอัดด้วยเช่นกันซึ่งเป็นสิ่งที่สามารถบอกphpinfo()ได้ สิ่งเดียวที่ฉันจินตนาการได้คือฉันต้องมีขนาดบัฟเฟอร์ต่ำสุดก่อนเช่น 256 หรือมากกว่านั้น
Thomas Tempelmann

@ThomasTempelmann - ฉันไม่เห็นอะไรเลยในคำถามของคุณหรือคำตอบของฉันเกี่ยวกับ gzip (โดยปกติแล้วมันสมเหตุสมผลที่จะทำให้สถานการณ์ง่ายที่สุดก่อนที่จะเพิ่มความซับซ้อน) เพื่อสร้างเมื่อเซิร์ฟเวอร์กำลังส่งข้อมูลคุณสามารถใช้แพ็คเก็ตดมกลิ่นของปลั๊กอินเบราว์เซอร์ (เช่นไวโอลิน, tamperdata, ฯลฯ ) จากนั้นหากคุณพบว่าเว็บเซิร์ฟเวอร์เก็บผลสคริปต์ทั้งหมดจนกระทั่งออกโดยไม่คำนึงถึงการล้างข้อมูลคุณต้องแก้ไขการกำหนดค่าเว็บเซิร์ฟเวอร์ของคุณ (ไม่มีสิ่งใดที่สคริปต์ PHP ของคุณสามารถทำได้ในกรณีนี้)
ปีเตอร์

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

1

หากคุณไม่ต้องการให้เต็มเป่า ActiveMQ ผมแนะนำให้พิจารณาRabbitMQ RabbitMQ คือการส่งข้อความที่มีน้ำหนักเบาที่ใช้มาตรฐาน AMQP

ฉันแนะนำให้ดูที่php-amqplib - ไลบรารีไคลเอนต์ AMQP ยอดนิยมเพื่อเข้าถึงโบรกเกอร์ข้อความที่ใช้ AMQP


0

ฉันคิดว่าคุณควรลองใช้เทคนิคนี้มันจะช่วยให้โทรได้มากเท่าที่คุณชอบทุกหน้าจะทำงานพร้อมกันโดยไม่ต้องรอการตอบกลับแต่ละหน้าเป็นแบบอะซิงโครนัส

cornjobpage.php // mainpage

    <?php

post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue");
//post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue2");
//post_async("http://localhost/projectname/otherpage.php", "Keywordname=anyValue");
//call as many as pages you like all pages will run at once independently without waiting for each page response as asynchronous.
            ?>
            <?php

            /*
             * Executes a PHP page asynchronously so the current page does not have to wait for it to     finish running.
             *  
             */
            function post_async($url,$params)
            {

                $post_string = $params;

                $parts=parse_url($url);

                $fp = fsockopen($parts['host'],
                    isset($parts['port'])?$parts['port']:80,
                    $errno, $errstr, 30);

                $out = "GET ".$parts['path']."?$post_string"." HTTP/1.1\r\n";//you can use POST instead of GET if you like
                $out.= "Host: ".$parts['host']."\r\n";
                $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
                $out.= "Content-Length: ".strlen($post_string)."\r\n";
                $out.= "Connection: Close\r\n\r\n";
                fwrite($fp, $out);
                fclose($fp);
            }
            ?>

testpage.php

    <?
    echo $_REQUEST["Keywordname"];//case1 Output > testValue
    ?>

PS: ถ้าคุณต้องการส่งพารามิเตอร์ url เป็นลูปให้ทำตามคำตอบนี้: https://stackoverflow.com/a/41225209/6295712


0

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

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


-4

PHP เป็นภาษาเดียว threaded ดังนั้นไม่มีทางที่จะเริ่มต้นอย่างเป็นทางการเป็นกระบวนการที่ไม่ตรงกันกับมันอื่น ๆ กว่าการใช้หรือexec popenมีการโพสต์บล็อกเกี่ยวกับที่อยู่ที่นี่ ความคิดของคุณสำหรับคิวใน MySQL เป็นความคิดที่ดีเช่นกัน

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


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

ตัวอย่างเช่น: การส่งอีเมลผ่าน Google Apps Smtp ด้วย ssl และพอร์ต 465 จะใช้เวลานานกว่าปกติ
Gixty
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.