Position actuelle: Accueil> Derniers articles> Exemple de la façon d'implémenter les fichiers XML d'analyse multipliés via XML_PARSE

Exemple de la façon d'implémenter les fichiers XML d'analyse multipliés via XML_PARSE

M66 2025-04-26

Lorsque vous travaillez avec de grands fichiers XML, l'analyse unique peut provoquer une utilisation excessive de mémoire ou un temps d'exécution excessif. PHP lui-même ne prend pas en charge nativement le «réel» multithreading (sauf si l'utilisation d'extensions telles que Pthreads ou Swoole), mais nous pouvons traiter de grands fichiers XML parallèles par (par exemple en utilisant ProC_Open ) pour améliorer l'efficacité de l'analyse.

Cet article montrera comment combiner la fonction XML_PARSE et Proc_Open pour implémenter l'analyse pseudo-multistrue des grands fichiers XML.

1. Pourquoi choisir XML_PARSE ?

XML_PARSE est l'une des fonctions d'analyse sous-jacente de PHP et fait partie de l'analyseur d'expatrié. Il prend en charge l'analyse basée sur des événements et est idéal pour diffuser de grands flux de données XML. XML_PARSE Économise plus de ressources que DOM Chargement du document entier en mémoire.

2. Idées de base pour simuler le multithreading

Nous ne pouvons pas laisser directement partager l'objet XML_PARSER , mais nous pouvons:

  1. Bloquer les grands fichiers XML (divisé par nœud) ;

  2. Utilisez proc_open () ou shell_exec () pour démarrer plusieurs processus enfants PHP;

  3. Chaque processus d'enfant analyse son propre bloc XML;

  4. Le processus principal recueille les résultats et les fusionne.

3. Exemple d'implémentation PHP

Supposons que nous ayons un grand fichier XML /data/huge.xml avec la structure suivante:

 <items>
  <item><id>1</id><name>Item 1</name></item>
  <item><id>2</id><name>Item 2</name></item>
  ...
</items>

1. Processus principal (maître.php)

 <?php

$sourceFile = '/data/huge.xml';
$tempDir = '/tmp/xml_chunks/';
$chunkSize = 1000; // Chaque procédé enfant analysant 1000 autonome <item>
$urls = [];

// Assurez-vous que le répertoire temporaire existe
if (!is_dir($tempDir)) {
    mkdir($tempDir, 0777, true);
}

// Diviser XML document
$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);

// Appel parallèle worker Analyseur(Peut être changé en curl_multi_exec Améliorer l&#39;efficacité)
foreach ($urls as $url) {
    shell_exec("php worker.php '{$url}' > /dev/null &");
}

echo "Commencé " . count($urls) . " autonome解析任务。\n";

2. Script d'analyse de sous-processus (Worker.php)

 <?php

if ($argc < 2) {
    exit("Veuillez passer XML document路径参数\n");
}

$xmlFile = urldecode($argv[1]);

if (!file_exists($xmlFile)) {
    exit("document不存在: $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') {
        // Exemple:将解析结果保存到document或数据库
        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 erreur: %s", xml_error_string(xml_get_error_code($parser))));
}
fclose($fp);
xml_parser_free($parser);

echo "L&#39;analyse est terminée: $xmlFile\n";

4. Performance et précautions

  • Amélioration des performances : sur les processeurs multicœurs, chaque processus d'enfant s'exécute indépendamment, ce qui peut accélérer la vitesse d'analyse globale en parallèle.

  • Contrôle de la mémoire : la quantité de données traitées par chaque processus enfant est contrôlable pour éviter l'éclatement de la mémoire.

  • Sécurité : Assurez-vous que le chemin du fichier n'est pas directement passé par les paramètres d'URL dans l'environnement de production et que la vérification de la liste blanche doit être ajoutée.

  • Gestion des processus : vous pouvez utiliser pcntl_fork ou swoole pour remplacer shell_exec pour obtenir une gestion plus stable du processus des enfants.

V. Conclusion

Bien que PHP lui-même ne soit pas un langage idéal pour le traitement simultané, via les techniques XML_PARSE et de contrôle des processus, nous pouvons toujours analyser efficacement les grands fichiers XML. Cette méthode convient particulièrement aux scénarios de tâche qui nécessitent une efficacité telle que le traitement des journaux et l'importation de données.

Si d'autres améliorations sont nécessaires, il est recommandé de réécrire le module d'analyse dans des langages concurrencés tels que Go / Python, puis de le planifier via PHP.