我认为问题是你为什么经常运行这个脚本?您是一遍又一遍地对相同的数据执行计算(字符串替换),还是每次都对不同的数据执行计算?
如果答案是前者,那么在 PHP 端提高性能就没有什么可做的了。您可以通过其他方式提高性能,例如使用更好的硬件(SSD 用于更快地读取/写入文件)、多核 CPU 以及将数据分解为同时运行多个脚本以同时处理数据的小块,以及更快的 RAM (即更高的总线速度)。
如果答案是后者,那么您可能需要考虑使用诸如 memcached 或 reddis(键/值缓存存储)之类的东西来缓存结果,以便您只能执行一次计算,然后它只是从内存中线性读取,这非常便宜且几乎不涉及 CPU 开销(您也可以在此级别使用 CPU 缓存)。
PHP 中的字符串操作已经很便宜了,因为 PHP 字符串本质上只是字节数组。在将文件读入内存并将其存储在字符串中时,PHP 几乎没有任何开销。如果您有一些示例代码来演示您在哪里看到性能问题和一些基准数字,我可能会有一些更好的建议,但现在看起来您需要根据您的潜在需求重构您的方法。
例如,当您在不同情况下处理数据时,需要单独考虑 CPU 和 I/O 成本。I/O 涉及阻塞,因为它是一个系统调用。这意味着您的 CPU 必须等待更多数据通过线路(同时您的磁盘将数据传输到内存)才能继续处理或计算该数据。你的 CPU 总是比内存快得多,而内存总是比磁盘快得多。
这是一个简单的基准来向您展示差异:
/* First, let's create a simple test file to benchmark */
file_put_contents('in.txt', str_repeat(implode(" ",range('a','z')),10000));
/* Now let's write two different tests that replace all vowels with asterisks */
// The first test reads the entire file into memory and performs the computation all at once
function test1($filename, $newfile) {
$start = microtime(true);
$data = file_get_contents($filename);
$changes = str_replace(array('a','e','i','o','u'),array('*'),$data);
file_put_contents($newfile,$changes);
return sprintf("%.6f", microtime(true) - $start);
}
// The second test reads only 8KB chunks at a time and performs the computation on each chunk
function test2($filename, $newfile) {
$start = microtime(true);
$fp = fopen($filename,"r");
$changes = '';
while(!feof($fp)) {
$changes .= str_replace(array('a','e','i','o','u'),array('*'),fread($fp, 8192));
}
file_put_contents($newfile, $changes);
return sprintf("%.6f", microtime(true) - $start);
}
上面的两个测试做同样的事情,但是当我使用更少量的数据(在这个测试中大约 500KB )时, Test2对我来说明显更快。
这是您可以运行的基准测试...
// Conduct 100 iterations of each test and average the results
for ($i = 0; $i < 100; $i++) {
$test1[] = test1('in.txt','out.txt');
$test2[] = test2('in.txt','out.txt');
}
echo "Test1 average: ", sprintf("%.6f",array_sum($test1) / count($test1)), "\n",
"Test2 average: ", sprintf("%.6f\n",array_sum($test2) / count($test2));
对我来说,上面的基准测试给出了Test1 average: 0.440795
and Test2 average: 0.052054
,这是一个数量级的差异,这只是对 500KB 的数据进行测试。现在,如果我将此文件的大小增加到大约 50MB,Test1实际上证明会更快,因为每次迭代的系统 I/O 调用更少(即我们只是在 Test1 中线性地从内存中读取),但更多的 CPU 成本(即我们每次迭代执行更大的计算)。事实证明,CPU 一次能够处理比 I/O 设备通过总线发送的数据量大得多的数据。
因此,在大多数情况下,这不是一个万能的解决方案。