日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

php并发取源码,PHP读取大文件源码示例-Swoole多进程读取大文件

發(fā)布時(shí)間:2025/3/12 php 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php并发取源码,PHP读取大文件源码示例-Swoole多进程读取大文件 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

PHP讀取大文件源碼示例,通過(guò)PHP讀取過(guò)大、超大型文件的思路及解決方案。

在日常讀取文件時(shí),若文件 不是很大,通常使用file_get_contents,將內(nèi)容一次性載入的變量中,也可以遠(yuǎn)程加載網(wǎng)頁(yè)或者遠(yuǎn)端文件。

若加載超過(guò)PHP限制的內(nèi)存大小,或者超過(guò)本機(jī)內(nèi)存大小的文件進(jìn)程就會(huì)報(bào)錯(cuò)或者崩掉。

為了解決這個(gè)問(wèn)題,我們采用使用完畢并釋放的原則來(lái)讀取大文件。

單線程讀入

如果不考慮多線程的情況下,單線程讀取大文件采用while fread就可以實(shí)現(xiàn)。

如下代碼

$handle = fopen("./big.txt", "rb");

while (!feof($handle)) {

$contents = fread($handle, 8192);

// 業(yè)務(wù)處理

unset($contents); // 釋放掉變量

}

fclose($handle);

feof是判斷是否到文件尾,如果沒(méi)有到文件尾,則會(huì)一直while循環(huán),并執(zhí)行讀取操作。每次讀取8192字節(jié),然后使用過(guò)后將其釋放掉。

往往很多文件并不是一行的,有多行內(nèi)容。需要將每行內(nèi)容讀取出來(lái)當(dāng)做一條數(shù)據(jù)處理,也可以使用fgets。

即如下代碼:

$handle = fopen("./big.txt", "rb");

while (!feof($handle)) {

$contents = fgets($handle, 1024);

// 業(yè)務(wù)處理

unset($contents); // 釋放掉變量

}

fclose($handle);

這里的fgets第二個(gè)參數(shù),默認(rèn)為1024字節(jié)。即默認(rèn)讀取一行數(shù)據(jù),如果一行數(shù)據(jù)小于1024字節(jié),則完整讀取。如果超出1024字節(jié),則只取前1024字節(jié)。遇到換行符"\n"或者"\r\n"或者結(jié)束符會(huì)停止讀取。

如果遇到變態(tài)的文件,很多行都只有1000長(zhǎng)度,某一行有8000長(zhǎng)度,如果在不清楚的情況下,就很難掌控,若要完整讀取就需要指定讀取的最大字節(jié),8000才能將每一行完整讀取。

還有一種方法就是自己處理?yè)Q行符。默認(rèn)讀取1024字節(jié),然后放置到內(nèi)存中,使用過(guò)后再將其釋放。這種操作很節(jié)省內(nèi)存,但是在邏輯處理上需要自己處理?yè)Q行符。

如,讀取1024字節(jié),沒(méi)有換行符,則保存數(shù)據(jù)繼續(xù)讀取。再讀取1024字節(jié),判斷其中是否有換行符,如果有則處理最開(kāi)始到換行符中的數(shù)據(jù)。再將剩下的數(shù)據(jù)保存,等待下一次讀取,直到整個(gè)文件讀取完畢。

$handle = fopen("./big.txt", "rb");

$contents = "";

while (!feof($handle)) {

$contents .= fread($handle, 8192);

// 判斷讀取到的內(nèi)容是否包含換行符,包含則進(jìn)入循環(huán)體

while(strpos($contents, "\n") !== false){

$eol_pos= strpos($contents, "\n");

$line = substr($contents, 0, $eol_pos);

// $line為一行的數(shù)據(jù),進(jìn)行業(yè)務(wù)處理,并釋放

unset($line);

$contents = substr($eol_pos, 0);// 將剩余內(nèi)容放置到變量中以供下次使用

}

}

fclose($handle);

多線程讀取

PHP默認(rèn)沒(méi)有多線程,這里可以采用多進(jìn)程的方式實(shí)現(xiàn),或者swoole的多進(jìn)程來(lái)實(shí)現(xiàn)。

例如讀取一個(gè)8GB文件,分8個(gè)線程,每個(gè)線程讀取1GB數(shù)據(jù)內(nèi)容。或者更多線程進(jìn)行拆分工作內(nèi)容。

獲取文件大小

首先第一步,就是獲取整個(gè)文件的體積大小,然后計(jì)算每個(gè)線程應(yīng)該負(fù)責(zé)處理的一部分內(nèi)容。

function length($filename)

{

$handle = fopen($filename, "rb");

$currentPos = ftell($handle);

fseek($handle, 0, SEEK_END);

$length = ftell($handle);

fseek($handle, $currentPos);

// $length 文件總長(zhǎng)度

return $length;

}

echo length("./big.txt");

處理邏輯實(shí)現(xiàn)過(guò)程

這里主要說(shuō)明下作了哪些內(nèi)容,首先是設(shè)定分配總的線程數(shù)。然后根據(jù)設(shè)置的線程數(shù),計(jì)算每個(gè)線程要讀取的數(shù)據(jù)大小,即從哪里開(kāi)始讀,讀到哪里結(jié)束。

然后必定會(huì)出現(xiàn)拆分后,讀到不完整行的情況,在這里來(lái)解決這種前半行或者后半行的意外情況。

解決邏輯就是,假設(shè)線程開(kāi)始的讀取位置在某一行的中間,我們一個(gè)字符向前移動(dòng),移動(dòng)到上個(gè)換行符(也可能是最開(kāi)始)即可獲取到整行文本內(nèi)容。

處理掉殘行數(shù)據(jù)之后,使用yield來(lái)傳遞數(shù)據(jù)給業(yè)務(wù)處理。

$filename = "./big.txt";

$maxProcess = 8;// 分配8個(gè)線程

$length = length($filename);

$singleProcessLength = ceil($length / $maxProcess);

// 線程負(fù)責(zé)讀取的內(nèi)容

function processRead($filename, $index, $singleProcessLength)

{

$fh = fopen($filename, 'r');

$beginPos = $index * $singleProcessLength;

//結(jié)束位置=線程序列*線程處理數(shù)據(jù)長(zhǎng)度+線程處理數(shù)據(jù) - 1 (長(zhǎng)度轉(zhuǎn)指針,實(shí)際結(jié)束指針小于結(jié)束長(zhǎng)度)

$endPos = $index * $singleProcessLength + $singleProcessLength - 1;

fseek($fh, $beginPos);

echo '線程:' . $index . ',起始位置:' . $beginPos . ',結(jié)束位置:' . $endPos . PHP_EOL;

//移動(dòng)到上個(gè)\n 以便首次順利獲取整行內(nèi)容

while (fseek($fh, -1, SEEK_CUR) === 0) {

if (fread($fh, 1) == "\n" || ftell($fh) <= 0) {

break;

}

fseek($fh, -1, SEEK_CUR);

}

echo '線程:' . $index . ',移動(dòng)完畢!!!!!' . PHP_EOL;

//整行讀取數(shù)據(jù)

//結(jié)束時(shí)位置超過(guò)預(yù)計(jì)結(jié)束位置是正常狀況,fgets 讀取一整行內(nèi)容

//預(yù)計(jì)結(jié)束位置可能在行內(nèi),所以產(chǎn)生不同結(jié)果。

while (ftell($fh) <= $endPos && !feof($fh)) {

yield $raw = fgets($fh);

}

echo '進(jìn)程' . $index . '結(jié)束時(shí) 指針位置:' . ftell($fh) . ', 應(yīng)該到:' . $endPos . PHP_EOL;

fclose($fh);

}

foreach(range(0,$maxProcess - 1) as $index){

// 多線程采用多線程的方式創(chuàng)建,這里采用yield回調(diào)。

foreach(processRead($filename, $index, $singleProcessLength) as $value){

// $value為每一行的內(nèi)容,處理后釋放

unset($value);

}

}

如上所述就是PHP的大文件讀取解決方案,大部分用于多線程讀取大文件場(chǎng)景。

總結(jié)

以上是生活随笔為你收集整理的php并发取源码,PHP读取大文件源码示例-Swoole多进程读取大文件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。