현재 위치: > 최신 기사 목록> XML_PARSE를 통해 멀티 스레드 파싱 XML 파일을 구현하는 방법의 예

XML_PARSE를 통해 멀티 스레드 파싱 XML 파일을 구현하는 방법의 예

M66 2025-04-26

대형 XML 파일로 작업 할 때 단일 스레드 구문 분석은 과도한 메모리 사용 또는 과도한 실행 시간을 유발할 수 있습니다. PHP 자체는 "실제"멀티 스레딩 ( PTHREADS 또는 SWOOLE과 같은 확장을 사용하지 않는 한)을 기본적으로 지원하지는 않지만 (예 : Proc_Open 사용) 구문 분석 효율을 향상시켜 큰 XML 파일을 병렬로 처리 할 수 ​​있습니다.

이 기사에서는 XML_PARSE 기능과 Proc_Open을 결합하여 큰 XML 파일의 의사-다일 리드 파싱을 구현하는 방법을 보여줍니다.

1. 왜 xml_parse를 선택합니까?

XML_PARSE 는 PHP의 기본 구문 분석 기능 중 하나이며 국외 파서의 일부입니다. 이벤트 기반 구문 분석을 지원하며 대형 XML 데이터 스트림을 스트리밍하는 데 이상적입니다. XML_PARSE는 전체 문서를 메모리에로드하는 것보다 더 많은 리소스를 저장합니다.

2. 멀티 스레딩 시뮬레이션을위한 기본 아이디어

여러 스레드가 XML_PARSER 객체를 직접 공유하게 할 수는 없지만 다음을 수행 할 수 있습니다.

  1. 큰 XML 파일을 차단 (노드로 나눈) ;

  2. Proc_open () 또는 Shell_Exec ()를 사용하여 여러 PHP 자식 프로세스를 시작하십시오.

  3. 각 어린이는 자체 XML 블록을 구문 분석합니다.

  4. 주요 프로세스는 결과를 수집하여 병합합니다.

3. PHP 구현 예

다음 구조가있는 큰 XML 파일 /data/huge.xml 이 있다고 가정합니다.

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

1. 메인 프로세스 (Master.php)

 <?php

$sourceFile = '/data/huge.xml';
$tempDir = '/tmp/xml_chunks/';
$chunkSize = 1000; // 각 어린이 프로세스 구문 분석 1000 개별 <item>
$urls = [];

// 임시 디렉토리가 있는지 확인하십시오
if (!is_dir($tempDir)) {
    mkdir($tempDir, 0777, true);
}

// 나뉘다 XML 문서
$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);

// 병렬 호출 worker 파서(변경할 수 있습니다 curl_multi_exec 효율성을 향상시킵니다)
foreach ($urls as $url) {
    shell_exec("php worker.php '{$url}' > /dev/null &");
}

echo "시작 " . count($urls) . " 개별解析任务。\n";

2. 하위 프로세스 구문 분석 스크립트 (worker.php)

 <?php

if ($argc < 2) {
    exit("제발 통과하십시오 XML 문서路径参数\n");
}

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

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

echo "분석이 완료되었습니다: $xmlFile\n";

4. 성능 및 예방 조치

  • 성능 개선 : 멀티 코어 CPU에서 각 어린이 프로세스는 독립적으로 실행되므로 전체 구문 분석 속도를 동시에 속도로 높일 수 있습니다.

  • 메모리 제어 : 각 어린이 프로세스에서 처리 한 데이터의 양은 메모리 파열을 피하기 위해 제어 할 수 있습니다.

  • 보안 : 파일 경로가 프로덕션 환경에서 URL 매개 변수를 직접 전달하지 않도록하고 화이트리스트 검증을 추가해야합니다.

  • 프로세스 관리 : PCNTL_FORK 또는 SWOOLE을 사용하여 Shell_Exec을 대체하여보다 안정적인 아동 프로세스 관리를 달성 할 수 있습니다.

V. 결론

PHP 자체는 동시 처리에 이상적인 언어는 아니지만 XML_PARSE 및 프로세스 제어 기술을 통해 큰 XML 파일을 효율적으로 구문 분석 할 수 있습니다. 이 방법은 로그 처리 및 데이터 가져 오기와 같은 효율성이 필요한 작업 시나리오에 특히 적합합니다.

추가 개선이 필요한 경우, Go/Python과 같은 동시성 친화적 인 언어로 구문 분석 모듈을 다시 작성한 다음 PHP를 통해 예약하는 것이 좋습니다.