当前位置: 首页 > news >正文

PHP流式处理与生成器应用

PHP流式处理与生成器应用

处理大文件或大数据集时,一次性加载到内存会导致内存溢出。PHP的生成器和流式处理可以解决这个问题。今天说说怎么用生成器处理大数据。

生成器用yield关键字,可以在不生成整个数组的情况下进行迭代。每次迭代到yield时,函数会暂停并保存状态,下次迭代再继续。

```php
// 生成器:逐行读取大文件
function readLargeFile(string $path): Generator
{
$handle = fopen($path, 'r');
if ($handle === false) {
throw new RuntimeException("无法打开文件: $path");
}

$lineNumber = 0;
while (($line = fgets($handle)) !== false) {
$lineNumber++;
yield $lineNumber => trim($line);
}

fclose($handle);
}

// 使用生成器
$file = '/tmp/large_file.txt';
file_put_contents($file, implode("\n", range(1, 1000000)));

$start = memory_get_usage(true);
foreach (readLargeFile($file) as $num => $line) {
if ($num % 100000 === 0) {
echo "已处理 {$num} 行\n";
}
}
echo "内存使用: " . (memory_get_usage(true) - $start) / 1024 . " KB\n";
?>
```

生成器可以用于生成数据,而不需要预先创建数组:

```php
// 生成所有数据的生成器
function generateRange(int $start, int $end, int $step = 1): Generator
{
for ($i = $start; $i <= $end; $i += $step) {
yield $i;
}
}

// 斐波那契数列生成器
function fibonacci(int $limit): Generator
{
$a = 0;
$b = 1;
for ($i = 0; $i < $limit; $i++) {
yield $a;
[$a, $b] = [$b, $a + $b];
}
}

echo "斐波那契前10: ";
foreach (fibonacci(10) as $num) {
echo "$num ";
}
echo "\n";

// 分页数据生成器
function paginateGenerator(callable $fetcher, int $perPage = 100): Generator
{
$page = 1;
while (true) {
$items = $fetcher($page, $perPage);
if (empty($items)) break;

foreach ($items as $item) {
yield $item;
}

if (count($items) < $perPage) break;
$page++;
}
}

// 模拟从数据库分页查询
function fetchFromDb(int $page, int $perPage): array
{
$start = ($page - 1) * $perPage;
if ($start >= 1000) return [];

return array_map(fn($i) => "item_" . ($start + $i), range(1, $perPage));
}

$count = 0;
foreach (paginateGenerator('fetchFromDb', 50) as $item) {
$count++;
}
echo "生成器获取了 {$count} 条数据\n";
?>
```

生成器还可以用作协程,实现简单的协作式多任务:

```php
class Task
{
private Generator $coroutine;
private string $name;

public function __construct(string $name, Generator $coroutine)
{
$this->name = $name;
$this->coroutine = $coroutine;
}

public function run(): bool
{
if ($this->coroutine->valid()) {
echo "运行任务: {$this->name}\n";
$this->coroutine->next();
return true;
}
return false;
}

public function isFinished(): bool
{
return !$this->coroutine->valid();
}
}

class Scheduler
{
private array $tasks = [];

public function add(Task $task): void
{
$this->tasks[] = $task;
}

public function run(): void
{
while (!empty($this->tasks)) {
$task = array_shift($this->tasks);
$task->run();

if (!$task->isFinished()) {
$this->tasks[] = $task;
} else {
echo "任务完成\n";
}
}
}
}

$scheduler = new Scheduler();

$scheduler->add(new Task('A', (function () {
yield;
echo "任务A步骤2\n";
yield;
echo "任务A步骤3\n";
})()));

$scheduler->add(new Task('B', (function () {
yield;
echo "任务B步骤2\n";
yield;
})()));

$scheduler->run();
?>
```

管道处理可以把多个生成器连接起来,形成处理流水线:

```php
function generateNumbers(int $count): Generator
{
for ($i = 1; $i <= $count; $i++) {
yield $i;
}
}

function filterEven(Generator $input): Generator
{
foreach ($input as $value) {
if ($value % 2 === 0) {
yield $value;
}
}
}

function multiply(Generator $input, int $factor): Generator
{
foreach ($input as $value) {
yield $value * $factor;
}
}

function limit(Generator $input, int $count): Generator
{
$i = 0;
foreach ($input as $value) {
if ($i++ >= $count) break;
yield $value;
}
}

// 管道:生成数字 -> 过滤偶数 -> 乘以3 -> 取前5个
$pipeline = limit(
multiply(
filterEven(
generateNumbers(100)
),
3
),
5
);

echo "管道处理结果: ";
foreach ($pipeline as $value) {
echo "$value ";
}
echo "\n";
?>
```

生成器的内存优势很明显。生成一百万个数字的数组会占用几十MB内存,而生成器只占几十字节。在处理大数据、大文件、大量数据库记录时,生成器是非常有用的工具。

http://www.jsqmd.com/news/958806/

相关文章:

  • 如何高效使用ImDisk虚拟磁盘:Windows系统下的全能存储解决方案
  • 告别环境冲突!用Anaconda3虚拟环境独立安装LabelImg(附Qt5配置)
  • 2026昆明配眼镜推荐:五家渠道横向对比与选购思路 - 配眼镜新资讯
  • 当十年前的至强处理器遇上现代大模型:本地推理的极致优化指南
  • 名酒回收联系渠道解析:抚顺市,丹东市,盘锦市,吉林人头马回收/吉林威士忌回收/吉林白兰地回收/吉林轩尼诗回收/哈尔滨名庄红酒回收/选择指南 - 优质品牌商家
  • 别再死记硬背GNN公式了!用‘信息传递’的视角,5分钟图解GCN与GraphSAGE
  • 用C++和pcb-tools搞定Gerber文件解析:一个PCB缺陷检测项目的实战起点
  • 2026年珠片绣口碑排名,哪家更值得选择? - myqiye
  • 2026长沙配眼镜推荐看这篇,五家店从验光到售后全解析 - 配眼镜新资讯
  • 用Python实战马氏性检验:从数据清洗到卡方检验的完整流程(附代码避坑)
  • 2026昆明配眼镜推荐指南:五家配镜渠道深度解析 - 配眼镜新资讯
  • 昆明配眼镜推荐2026实测:五家店配镜真实体验逐一对比 - 配眼镜新资讯
  • 炉石传说脚本自动化:从基础操作到智能决策的完整指南
  • 2026年海关数据平台费用分析,苏维智搜贵吗? - myqiye
  • 别再只会用双线性插值了!PyTorch中nn.Upsample与转置卷积的实战对比与选择指南
  • Veo 2时长限制真相曝光(2024 Q3实测数据+GPU显存占用热力图):超时崩溃前最后37毫秒发生了什么?
  • 重构活动执行基线:营销活动SOP管理工具 2026 的技术内核
  • 别再手动敲Git命令了!用Pycharm 2023.3的图形化界面搞定版本控制(附GitHub配置)
  • 解决AI改文件翻车难题:一套自研沙盒版本机制,让浏览器Agent拥有后悔药
  • 从压缩文件到网络传输:用C++实现哈夫曼编码,并对比string和char*两种方案的性能差异
  • 2026年近期河北沧州钢套钢保温钢管厂家选择指南与优质服务商解析 - 2026年企业资讯
  • 2026年装饰设计品牌企业排名:高性价比的名匠装饰推荐 - myqiye
  • 探寻2026年当下湖南保健品标签优质厂家的核心竞争力:以湖南富林标签为例 - 2026年企业资讯
  • YOLOv11涨点改进| TGRS 2026 |特征融合改进篇| 引入DFAM差异特征频域注意力融合模块,发论文热点创新,强化细节与边缘特征,提高对小目标和弱特征目标的感知能力,YOLOv11有效涨点
  • 2026昆明配眼镜推荐去哪家,五家门店全方位实测对比 - 配眼镜新资讯
  • 2026倒置LED荧光显微镜技术解析与主流机型参考:电动荧光模块/研究级荧光显微镜/荧光倒置显微镜/荧光成像显微镜/选择指南 - 优质品牌商家
  • ECharts中国地图绘制保姆级教程:从获取china.js到完整配置(含避坑指南)
  • PHP正则表达式性能优化指南
  • 2026北京老酒回收机构评测:北京名酒回收/北京洋酒回收/北京老酒回收回收/北京茅台回收/北京闲置酒水回收/北京专业洋酒回收/选择指南 - 优质品牌商家
  • 高考失利到哪儿复读好!