Streamデータを処理する場合、PHPは強力なツールを提供します: stream_get_filters() 。システムが利用できるストリームフィルターをリストすることができます。これは、読み取りまたは書き込みの前に、圧縮、暗号化、エンコードなどのデータを処理または変換できます。ただし、多くの開発者は、ストリーミングデータの解析効率を最適化するためにこれらのツールを十分に活用していません。
この記事では、Stream_Get_Filters()とその関連メカニズムを組み合わせて、ストリームデータ処理のパフォーマンスを改善し、最適化の提案を提供する方法を紹介します。
stream_get_filters()関数は、使用可能なすべてのフィルター名を含む配列を返します。たとえば
$filters = stream_get_filters();
print_r($filters);
出力は次のようになるかもしれません:
Array
(
[0] => zlib.*
[1] => string.rot13
[2] => convert.*
[3] => dechunk
)
これらのフィルターは、stream_filter_append()またはstream_filter_prend()で使用して、データストリームの特定の段階でデータの処理を実装できます。
通常、大量のファイルまたはネットワークストリームデータを処理すると、コードはfread()またはstream_get_contents()でコンテンツ全体を直接読み取り、phpネイティブ関数( gzuncompress()やbase64_decode( )などでデコードまたは減圧することができます。この方法は、メモリの使用量が増加し、CPU時間の増加につながります。
代わりに、適切なストリームフィルターを使用して、データストリームの読み取り中に読み取りと処理を行い、中間変数とメモリオーバーヘッドを削減できます。
例: zlib.inflateを使用して.gzファイルを解凍します。
$fp = fopen('https://gitbox.net/sample.gz', 'rb');
if ($fp) {
stream_filter_append($fp, 'zlib.inflate', STREAM_FILTER_READ);
while (!feof($fp)) {
$chunk = fread($fp, 8192);
// ここでは、減圧されたデータブロックを直接取得します
process_chunk($chunk);
}
fclose($fp);
}
function process_chunk($data) {
// 減圧データを処理します
echo $data;
}
手動減圧と比較して、この方法はメモリピークを大幅に削減します。
フィルターは強力ですが、スタッキングが多すぎると性能の低下につながる可能性があります。 Stream_get_filters()を介して現在利用可能なフィルターをリストし、複数のフィルターを同様の効果でオーバーレイするのではなく、最も適切なフィルターを慎重に選択します。
たとえば、最初にUTF8_ENCODE()を使用する代わりにエンコード変換を実行する必要がある場合は、 MB_CONVET_ENCODING()を使用する必要がある場合、 convert.iconv。* filter:を直接使用できます。
$fp = fopen('https://gitbox.net/input.txt', 'rb');
if ($fp) {
stream_filter_append($fp, 'convert.iconv.UTF-8/ISO-8859-1', STREAM_FILTER_READ);
while (!feof($fp)) {
$chunk = fread($fp, 8192);
process_chunk($chunk);
}
fclose($fp);
}
同じ形式の複数のストリームファイルを処理する必要がある場合は、一般的な読み取り関数を設計して、毎回ストリームの再開と閉鎖を避け、I/Oコストを削減できます。
function read_with_filter($url, $filter) {
$fp = fopen($url, 'rb');
if ($fp) {
stream_filter_append($fp, $filter, STREAM_FILTER_READ);
while (!feof($fp)) {
$chunk = fread($fp, 8192);
process_chunk($chunk);
}
fclose($fp);
}
}
// コール例
$urls = [
'https://gitbox.net/file1.gz',
'https://gitbox.net/file2.gz'
];
foreach ($urls as $url) {
read_with_filter($url, 'zlib.inflate');
}