CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.
Bài viết trên blog CFSDN này cung cấp những phân tích chuyên sâu về đa luồng (giả) và đa xử lý trong PHP, được tác giả sưu tầm và biên soạn. Nếu bạn quan tâm đến bài viết này thì nhớ like nhé.
(Giả) đa luồng: Với sự trợ giúp của các lực bên ngoài, chúng tôi sử dụng tính năng đa luồng của chính máy chủ WEB để xử lý. Chúng tôi gọi chương trình mà chúng tôi cần triển khai đa luồng nhiều lần từ máy chủ WEB. LƯU Ý: Chúng tôi biết rằng bản thân PHP không hỗ trợ đa luồng, nhưng máy chủ WEB của chúng tôi có hỗ trợ đa luồng. Nói cách khác, nó có thể được nhiều người truy cập cùng một lúc. -threading trong PHP. Giả sử bây giờ chúng ta có tệp a.php đang chạy. Nhưng trong chương trình, tôi yêu cầu máy chủ WEB chạy một tệp b.php khác, sau đó hai tệp sẽ được thực thi cùng một lúc. yêu cầu liên kết được gửi đi, máy chủ WEB sẽ thực thi nó, bất kể máy khách đã thoát hay chưa) Đôi khi, Những gì chúng ta muốn chạy không phải là một tệp khác mà là một phần mã trong tệp này. Chúng ta nên làm gì? Trên thực tế, chúng ta có thể sử dụng các tham số để kiểm soát chương trình a.php nào sẽ chạy.
Sao chép mã Mã này như sau:
hàm runThread(){
$fp = fsockopen('localhost', 80, $errno, $errmsg);
kết quả đầu ra($fp, "GET /a.php?act=brnrn");//Tham số thứ hai ở đây là tiêu đề yêu cầu được chỉ định trong giao thức HTTP. Nếu bạn không hiểu, vui lòng xem định nghĩa trong RFC ; ; &nbs p;
fclose($fp);
}
hàm a(){
$fp = fopen('result_a.log', 'w');
fputs($fp, 'Đặt trong ' . Date('h:i:s', time()) . (double)microtime() . "rn");
fclose($fp);
}
hàm b(){
$fp = fopen('result_b.log', 'w');
fputs($fp, 'Đặt trong ' . Date('h:i:s', time()) . (double)microtime() . "rn");
fclose($fp);
}
nếu(!isset($_GET['act'])){ $_GET['act'] = 'a';};
nếu($_GET['act'] == 'a'){
chạyThread();
một();
}nếu không thì($_GET['act'] == 'b'){
b();
};
?>
Mở result_a.log và result_b.log và so sánh thời gian truy cập của hai tệp này. Bạn sẽ thấy rằng hai tệp này thực sự đang chạy trong các luồng khác nhau. Trên đây chỉ là một ví dụ đơn giản, bạn có thể cải thiện nó. sang các dạng khác. Hiện nay tính năng đa luồng đã có sẵn trong PHP, một vấn đề nảy sinh, đó là vấn đề đồng bộ hóa. Chúng ta biết rằng bản thân PHP không hỗ trợ đa luồng nên không có gì giống như Java. Phương thức đồng bộ đã có. Vậy chúng ta nên thực hiện như thế nào?
。
1. Cố gắng không truy cập vào cùng một tài nguyên để tránh xung đột. Nhưng bạn có thể vận hành cơ sở dữ liệu cùng một lúc. Vì cơ sở dữ liệu hỗ trợ các hoạt động đồng thời, không ghi dữ liệu vào cùng một tệp trong PHP đa luồng. sử dụng các phương pháp khác để đồng bộ hóa.. chẳng hạn như gọi đàn để khóa tệp, v.v. Hoặc tạo một tệp tạm thời và đợi tệp biến mất trong một luồng khác while(file_exits('xxx')); tập tin khi tồn tại, Cho biết rằng luồng đang thực sự hoạt động. Nếu không có tệp như vậy, điều đó có nghĩa là các luồng khác đã phát hành tệp này.
2. Cố gắng không đọc dữ liệu từ socket mà runThread lấy sau khi thực hiện fputs. Vì vậy, để đạt được đa luồng, cần phải sử dụng chế độ không chặn, tức là quay lại ngay lập tức khi sử dụng chức năng như fgets. việc ghi dữ liệu sẽ bị lỗi. Nếu sử dụng chế độ chặn, chương trình không được coi là đa luồng. Nó phải đợi dữ liệu trên quay trở lại trước khi thực hiện chương trình sau. trong các tập tin hoặc dữ liệu bên ngoài. Nếu bạn thực sự muốn nó, chỉ cần sử dụng socket_set_nonblock($fp) để đạt được nó. Đã nói rất nhiều, điều này có ý nghĩa thực tế gì không? liên tục đọc tài nguyên mạng, tốc độ của mạng là nút cổ chai. Nếu hình thức này được áp dụng, nhiều luồng có thể được sử dụng để đọc các trang khác nhau cùng một lúc. Tôi đã tạo một chương trình có thể tìm kiếm thông tin từ các trang web của trung tâm mua sắm như 8848 và soaso. Ngoài ra còn có một chương trình đọc thông tin doanh nghiệp và danh bạ công ty từ trang web Alibaba và cũng sử dụng công nghệ này. Bởi vì cả hai chương trình đều phải kết nối liên tục với máy chủ của mình để đọc thông tin và lưu vào cơ sở dữ liệu. Việc sử dụng công nghệ này chỉ giúp loại bỏ tình trạng tắc nghẽn khi chờ phản hồi.
Đa quy trình: Việc sử dụng các Chức năng điều khiển quy trình của PHP (PCNTL/Chức năng điều khiển luồng) chỉ có thể được sử dụng trên Unix Like OS, không có trên Windows. Khi biên dịch php, bạn cần thêm --enable-pcntl và chỉ nên chạy ở chế độ CLI, không chạy trong môi trường máy chủ WEB. Sau đây là một mã kiểm tra ngắn:
Sao chép mã Mã này như sau:
khai báo(tích=1);
$bWaitFlag = FALSE; /// Có chờ quá trình kết thúc hay không
$intNum = 10; /// Tổng số tiến trình
$pids = array(); /// Xử lý mảng PID
echo ("Bắt đầu\n");
đối với($i = 0; $i < $intNum; $i++) {
$pids[$i] = pcntl_fork();/// Tạo một tiến trình con và bắt đầu mã chạy thử nghiệm từ dòng hiện tại và không kế thừa thông tin dữ liệu của tiến trình gốc
nếu(!$pids[$i]) {
// Mã tiến trình con Segment_Start
$str="";
ngủ(5+$i);
đối với ($j=0;$j<$i;$j++) {$str.="*";}
echo "$i -> " .time() . " $str \n";
ra();
// Mã tiến trình con Segment_End
}
}
nếu ($bWaitFlag)
{
đối với($i = 0; $i < $intNum; $i++) {
pcntl_waitpid($pids[$i], $status, WUNTRACED);
echo "chờ $i -> " .time() . "\n";
}
}
echo ("Kết thúc\n");
Từ khóa: CODE:[Copy toclipboard][qiao@oicq qiao]$ phptest.php Bắt đầu Kết thúc [qiao@oicq qiao]$ ps -aux | grep " php " qiao 32275 0,0 0,5 49668 6148pts / 1 S 14:03 0:00 / usr / local / php4 / b qiao 32276 0,0 0,5 49668 6152pts / 1 S 14:03 | | /usr/local/php4/b qiao 32281 0,0 0,5 49668 6152pts/1 S 14:03 0:00/usr/local/php4/b qiao 32282 0,0 0,5 49668 6152pts/1 S 14:03 | 0:00/usr/local/php4/b qiao 32286 0.0 0.0 1620 600pts/1 S 14:03 0:00 grep php [qiao@oicq qiao]$0 -> 1133503401 1 -> 1133503402 * 2 -> 1133503403 ** 3 -> 1133503404 *** 4 -> 1133503405 **** 5 -> 1133503406 ***** 6 -> 1133503407 ******* 7 -> 1133503408 ******* 8 - > 1133503409 ******** 9 -> 1133503410 ********** [qiao@oicq qiao]$ kích hoạt $bWaitFlag=TURE, kích hoạt khóa: CODE:[Copy toclipboard][qiao@oicq qiao]$phptest.php Start 0 -> 1133503602 Chờ đợi 0 -> 1133503602 1 -> 1133503603 * đợi 1 -> 1133503603 2 -> 1133503604 ** đợi 2 -> 1133503604 3 -> 1133503605 *** đợi 3 -> -> 1133503606 **** đợi 4 -> 1133503606 5 -> 1133503607 ***** đợi 5 -> 1133503607 6 -> 1133503608 ******* đợi 6 -> 1133503608 7 -> ******* đợi 7 -> 1133503609 8 -> 1133503610 ******** đợi 8 -> 1133503610 9 -> 1133503611 ********** đợi 9 -> 1133503611 Kết thúc [qiao @oicq qiao]$ một Nếu bạn muốn cài đặt một fork, bạn có thể sử dụng pcntl_fork() và bạn cần cài đặt nó , vui lòng cài đặt cài đặt mặc định, pcntl_fork() của một nhánh cụ thể Làm bông tuyết bông tuyết bông tuyết (cũng là bông tuyết bông tuyết bông tuyết Bị ràng buộc riêng lẻ, khai báo if(!$pids[$i]) Kiểm tra phần còn lại của hồ bơi. Nếu bạn có một bộ quần áo rẻ hơn một chút, ít tốn kém hơn, bạn cũng có thể có một bộ quần áo đắt tiền hơn một chút.
。
[Bài viết 2] Hãy thử thực thi đồng thời nhiều tiến trình của các tập lệnh dòng lệnh PHP. Ngoài fork, còn có một phương thức đồng thời khác trong cli. Hãy xem ví dụ của tôi: PHP không hỗ trợ đa luồng, nhưng chúng ta có thể giải quyết vấn đề bằng cách chuyển đổi. nó thành "đa tiến trình". Vì pcntl_fork trong PHP chỉ có thể được sử dụng trên nền tảng Unix nên bài viết này cố gắng sử dụng popen để thay thế. Đây là một ví dụ: Mã chương trình con được gọi song song:
Sao chép mã Mã này như sau:
nếu($argc==1){
echo("argv\n");
}
$arg = $argv[1];
đối với ($i = 0; $i < 10; $i++)
{
echo($i.".1.".time()." exec $arg \n");
nếu($arg=='php2'){
ngủ(1);
echo($i.".2.".time()." exec $arg \n");
ngủ(1);
}khác{
ngủ(1);
}
}
?>
Chương trình gọi chính gọi tiến trình con và đồng thời thu thập đầu ra của chương trình con.
Sao chép mã Mã này như sau:
báo cáo lỗi(E_ALL);
$handle1 = popen('php sub.php php1', 'r');
$handle2 = popen('php sub.php php2', 'r');
$handle3 = popen('php sub.php php3', 'r');
echo "'$handle1'; " .gettype($handle1) . "\n";
echo "'$handle2'; " .gettype($handle2) . "\n";
echo "'$handle3'; " .gettype($handle3) . "\n";
//ngủ(20);
trong khi(!feof($handle1) || !feof($handle2) || !feof($handle3) )
{
$read = fgets($handle1);
echo $đọc;
$read = fgets($handle2);
echo $đọc;
$read = fgets($handle3);
echo $đọc;
}
pclose($handle1);
pclose($handle2);
pclose($handle3);
Ví dụ: C:\my_hunter>php exec.php 'Id tài nguyên #4'; tài nguyên 'Id tài nguyên #5'; tài nguyên 'Id tài nguyên #6'; tài nguyên 0.1.1147935331 exec php1 0.1.1147935331 exec php2 0.1.1147935331 exec php3 1.1.1147935332 exec php1 0.2.1147935332 exec php2 1.1.1147935332 exec php3 2.1.1147935333 exec php1 1.1.1147935333 exec php2 2.1.1147935333 exec php3 3.1.1147935334 exec php1 1.2.1147935334 thực thi php2 3.1.1147935334 thực thi php3 4.1.1147935335 thực hiện php1 2.1.1147935335 thực hiện php2 4.1.1147935335 thực hiện php3 5.1.1147935336 thực hiện php1 2.2.1147935336 thực hiện php2 5.1.1147935336 thực hiện php3 6.1.1147935337 thực hiện php1 3.1.1147935337 thực hiện php2 6.1.1147935337 thực hiện php3 7.1.1147935338 thực hiện php1 3.2.1147935338 thực thi php2 7.1.1147935338 thực thi php3 8.1.1147935339 thực thi php1 4.1.1147935339 thực thi php2 8.1.1147935339 thực thi php3 9.1.1147935340 thực thi php1 4.2.1147935340 thực thi php2 9.1.1147935340 thực thi php3 5.1.1147935341 thực thi php2 5.2.1147935342 thực thi php2 6.1.1147935343 thực thi php2 6.2.1147935344 thực thi php2 7.1.1147935345 thực thi php2 7.2.1147935346 thực thi php2 8.1.1147935347 thực thi php2 8.2.1147935348 thực thi php2 9.1.1147935349 thực thi php2 9.2.1147935350 thực thi php2 **总结:** **主程序循环等待子进程, 通过fgets或fread把子进程的输出获取出来 , 从时间戳上看,的确实现了并发执行。** ---------------------------- ------------------- 以后的改进: * popen打开的句柄是单向的,如果需要向子进程交互,可以使用proc_open *使用数组和子函数代替while(!feof($handle1)|| !feof($handle2) || !feof($handle3) )这种龌龊的写法 * 用fread一次把子进程已经产生的输出取完,而不是每次一行。 vỏ sò, vỏ sò, một công cụ hỗ trợ tốt
Sao chép mã Mã này như sau:
/*
người quản lý nhiệm vụ chính
Thực hiện đồng thời một danh sách các nhiệm vụ con
*/
bao gồm("../common/conf.php");
bao gồm("../common/function.php");
//Số tiến trình đã bắt đầu
$exec_number = 40 ;
/***** chủ yếu ********/
nếu($argc==1){
echo("đối số\n");
}
$taskfile = $argv[1];
//danh sách nhiệm vụ
$tasklist = tệp($taskfile);
$tasklist_len = đếm($tasklist);
$tasklist_pos = 0;
$handle_list = mảng();
trong khi(1)
{
// Nếu danh sách tiến trình con trống, hãy điền vào danh sách tiến trình con
nếu($exec_number > count($handle_list) &&
$tasklist_pos < $tasklist_len)
{
đối với($i=$tasklist_pos; $i<$tasklist_len; )
{
$command = $tasklist[$i] ;
$handle_list[] = popen($lệnh, "r");
tolog("bắt đầu nhiệm vụ \t ".$tasklist[$i]);
$i++;
nếu($exec_number == count($handle_list)) ngắt;
}
$tasklist_pos = $i;
}
//Nếu danh sách tiến trình con trống, thoát
nếu(0 == count($handle_list))
{
phá vỡ;
}
// Kiểm tra đầu ra của danh sách tiến trình con, đóng tiến trình con đã dừng và ghi lại nó
$end_handle_keys = mảng();
foreach($handle_list là $key => $handle)
{
//$str = fgets($xử lý, 65536);
$str = fread($xử lý, 65536);
echo($str);
nếu(feof($handle))
{
$end_handle_keys[] = $key;
pclose($xử lý);
}
}
// Loại bỏ tiến trình con đang dừng
foreach($end_handle_keys là $key)
{
bỏ đặt($handle_list[$key]);
//var_dump($handle_list);
//ra;
}
}
tolog("\n\n****************** kết thúc*********************\ n\n", "" , đúng);
Đính kèm một đoạn mã để tiếp nhận đa tiến trình của Socket:
Sao chép mã Mã này như sau:
LÀM {
nếu (($msgsock = socket_accept($sock)) < 0) {
echo "socket_accept() không thành công: lý do: " . socket_strerror($msgsock) . "\n";
phá vỡ;
}
$pid = pcntl_fork();
nếu ($pid == -1) {
die('không thể fork');
} nếu không thì (!$pid) {
.....
socket_write($msgsock, $msg, strlen($msg));
LÀM {
......
} while (đúng);
socket_close($msgsock);
}
} while (đúng);
。
Cuối cùng, bài viết này về phân tích chuyên sâu về đa luồng (giả) và đa xử lý trong PHP kết thúc ở đây. Nếu bạn muốn biết thêm về phân tích chuyên sâu về đa luồng (giả) và đa xử lý trong PHP. , vui lòng tìm kiếm các bài viết của CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Tôi là một lập trình viên xuất sắc, rất giỏi!