Bei der Arbeit mit großen XML-Dateien kann eine Single-Thread-Parsen zu übermäßigen Speicherverbrauch oder zu einer übermäßigen Ausführungszeit führen. PHP selbst unterstützt "Real" Multithreading nicht nativ (es sei denn, die Verwendung von Erweiterungen wie PTHREADS oder SWOOLE), aber wir können jedoch parallel große XML -Dateien verarbeiten, um (z. B. mit Proc_open ) zu verbessern, um die Parsing -Effizienz zu verbessern.
In diesem Artikel wird gezeigt, wie die Funktion XML_Parse und Proc_open kombiniert werden, um die Pseudo-Multithread-Parsen von großen XML-Dateien zu implementieren.
xml_parse ist eine der zugrunde liegenden Parsingfunktionen von PHP und Teil des Expat -Parsers. Es unterstützt die ereignisbasierte Parsen und ist ideal für das Streamieren großer XML-Datenströme. xml_parse spart mehr Ressourcen als DOM, das das gesamte Dokument in den Speicher lädt.
Wir können nicht direkt zulassen, dass mehrere Threads das XML_PARSER -Objekt teilen, aber wir können:
Block große XML -Dateien (geteilt durch den Knoten) ;
Verwenden Sie Proc_open () oder Shell_exec () , um mehrere PHP -Kinderprozesse zu starten.
Jedes Kinderprozess analysiert seinen eigenen XML -Block;
Der Hauptprozess sammelt die Ergebnisse und verschmilzt sie.
Angenommen, wir haben eine große XML -Datei /data/huge.xml mit der folgenden Struktur:
<items>
<item><id>1</id><name>Item 1</name></item>
<item><id>2</id><name>Item 2</name></item>
...
</items>
<?php
$sourceFile = '/data/huge.xml';
$tempDir = '/tmp/xml_chunks/';
$chunkSize = 1000; // Jedes Kinderprozess -Parsen 1000 indival <item>
$urls = [];
// Stellen Sie sicher, dass das temporäre Verzeichnis existiert
if (!is_dir($tempDir)) {
mkdir($tempDir, 0777, true);
}
// Teilt XML dokumentieren
$handle = fopen($sourceFile, 'r');
$chunkIndex = 0;
$buffer = '';
$itemCount = 0;
while (($line = fgets($handle)) !== false) {
if (strpos($line, '<item>') !== false) {
$itemCount++;
}
$buffer .= $line;
if ($itemCount >= $chunkSize || feof($handle)) {
$chunkFile = $tempDir . "chunk_{$chunkIndex}.xml";
file_put_contents($chunkFile, "<items>\n" . $buffer . "\n</items>");
$urls[] = "http://m66.net/worker.php?file=" . urlencode($chunkFile);
$chunkIndex++;
$buffer = '';
$itemCount = 0;
}
}
fclose($handle);
// Parallelanruf worker Parser(Kann auf geändert werden auf curl_multi_exec Effizienz verbessern)
foreach ($urls as $url) {
shell_exec("php worker.php '{$url}' > /dev/null &");
}
echo "Begonnen " . count($urls) . " indival解析任务。\n";
<?php
if ($argc < 2) {
exit("Bitte geben Sie ein XML dokumentieren路径参数\n");
}
$xmlFile = urldecode($argv[1]);
if (!file_exists($xmlFile)) {
exit("dokumentieren不存在: $xmlFile\n");
}
$parser = xml_parser_create();
xml_set_element_handler($parser, "startElement", "endElement");
xml_set_character_data_handler($parser, "characterData");
$currentTag = '';
$currentItem = [];
function startElement($parser, $name, $attrs) {
global $currentTag;
$currentTag = strtolower($name);
}
function endElement($parser, $name) {
global $currentTag, $currentItem;
if (strtolower($name) == 'item') {
// Beispiel:将解析结果保存到dokumentieren或数据库
file_put_contents('/tmp/parsed_result.txt', json_encode($currentItem) . PHP_EOL, FILE_APPEND);
$currentItem = [];
}
$currentTag = '';
}
function characterData($parser, $data) {
global $currentTag, $currentItem;
if (trim($data)) {
$currentItem[$currentTag] = trim($data);
}
}
$fp = fopen($xmlFile, 'r');
while ($data = fread($fp, 4096)) {
xml_parse($parser, $data, feof($fp)) or
die(sprintf("XML Fehler: %s", xml_error_string(xml_get_error_code($parser))));
}
fclose($fp);
xml_parser_free($parser);
echo "Die Analyse ist abgeschlossen: $xmlFile\n";
Leistungsverbesserung : Bei Multi-Core-CPUs wird jeder Kinderprozess unabhängig ausgeführt, wodurch die Geschwindigkeit der Parallelen der Parallelen insgesamt beschleunigt wird.
Speicherregelung : Die Datenmenge, die von jedem untergeordneten Prozess verarbeitet werden, ist kontrollierbar, um das Speicherbacken zu vermeiden.
Sicherheit : Stellen Sie sicher, dass der Dateipfad nicht direkt URL -Parameter in der Produktionsumgebung übergeben wird, und die Überprüfung der Whitelist sollte hinzugefügt werden.
Prozessverwaltung : Sie können PCNTL_FORK oder SWOOLE verwenden, um Shell_exec zu ersetzen, um eine stabilere Kinderverarbeitung zu erreichen.
Obwohl PHP selbst keine ideale Sprache für die gleichzeitige Verarbeitung ist, können wir durch XML_Parse- und Prozesssteuerungstechniken große XML -Dateien effizient analysieren. Diese Methode eignet sich besonders für Aufgabenszenarien, die Effizienz wie Protokollverarbeitung und Datenimport erfordern.
Wenn weitere Verbesserungen benötigt werden, wird empfohlen, das Parsing-Modul in gleichzeiträdern freundlichen Sprachen wie GO/Python neu zu schreiben und es dann über PHP zu planen.