PHP 세그먼트 에서 큰 파일 읽 기 및 통계

7511 단어 PHP
다음으로 전송:https://www.yduba.com/biancheng-2442221832.html
때때로 우 리 는 로그 의 한 IP 가 최근 에 사 이 트 를 방문 한 상황 을 통계 하기 위해 큰 파일 을 조작 하고 분석한다.nginx 의 assess. log 파일 은 방문 로 그 를 기록 하지만 이 파일 은 일반적으로 매우 크다.PHP 를 사용 하면 어떻게 안에 있 는 정 보 를 집계 합 니까?여기 서 스스로 학습 총 결 을 하나 하 다.
이론 적 방법:
1. 파일 을 한꺼번에 메모리 에 읽 은 다음 한 줄 한 줄 분석 합 니 다. 예 를 들 어 함수 fileget_contents, fread, file 모두 조작 할 수 있 습 니 다.
2. 단계별 로 내용 을 메모리 에 읽 고 한 단락 씩 분석 합 니 다. 예 를 들 어 함수 fgets
이 두 가지 방법 은 모두 우리 의 조작 을 현실 화 할 수 있다.먼저 첫 번 째, 한꺼번에 내용 을 읽는다.이 방법 은 비교적 간단 하 다. 로 그 를 메모리 에 읽 은 후에 배열 로 변환 한 다음 에 배열 의 모든 열 을 분석 하 는 것 이다.코드 는 다음 과 같 습 니 다:
", $content);
    $writeres 		= fopen(WRITE_FILE_A, 'a+');

    //    WRITE_FILE
    flock($writeres, LOCK_EX);

    foreach($content_arr as $row)
    {
	if( strpos($row, "192.168.10.10") !== false )
	{
            fwrite($writeres, $row  . "
"); }     }     $em = memory_get_usage();     flock($writeres, LOCK_UN);     fclose($writeres);     $et = microtime( true );     echo "  file_get_contents:  :" . ($et - $st) . "
";     echo "  file_get_contents:  :" . ($em - $sm) . "
"; } writeLogA();

상기 코드 가 실 행 된 후에 IP 가 192.168.10.10 인 사용자 방문 로 그 를 임시 파일 에 쓸 수 있 습 니 다. 그러나 이때 문 제 는 코드 가 실 행 된 시간 과 소 모 된 메모리 가 매우 크다 는 것 입 니 다.특별 설명: 제 assets. log 는 크 지 않 습 니 다. 10 만 줄 정도 입 니 다. 여 기 는 프 리 젠 테 이 션 만 을 위 한 것 입 니 다. 실행 결 과 는 그림 과 같다.
현재 이 access. log 파일 은 크 지 않 습 니 다. 이미 이렇게 많은 시간 과 이렇게 큰 메모 리 를 소 모 했 습 니 다. 더 큰 파일 이 라면 요? 그래서 이런 방법 은 실 용적 이지 않 습 니 다.
또 다른 함수 fread 를 보십시오. fread 는 한 파일 의 내용 을 문자열 로 읽 는 것 입 니 다.
string fread ( resource $handle , int $length )

첫 번 째 매개 변 수 는 파일 시스템 포인터 입 니 다. fopen 에서 만 들 고 돌아 오 는 값 입 니 다. 두 번 째 매개 변 수 는 읽 을 크기 입 니 다.값 을 정확하게 읽 은 내용 으로 되 돌려 줍 니 다.
우 리 는 지금 위의 코드 중의 file 을get_contents 가 free ad 로 바 뀌 었 습 니 다.코드 는 다음 과 같 습 니 다:
", $content);

    $writeres 		= fopen(WRITE_FILE_B, 'a+');

    //    WRITE_FILE
    flock($writeres, LOCK_EX);

    foreach($content_arr as $row)
    {
        if( strpos($row, "[error]") !== false )
	{
	    fwrite($writeres, $row  . "
"); }     }     $em = memory_get_usage();     flock($writeres, LOCK_UN);     fclose($writeres);     fclose($fopenres);     $et = microtime( true );     echo "  fread:  :" . ($et - $st) . "
";     echo "  fread:  :" . ($em - $sm) . "
"; } writeLogB();

특별한 상황 이 없 으 면 이전 코드 보다 메모리 소모 가 더 클 것 이다.결과 그림 은 다음 과 같다.
이 점 은 PHP 공식 사이트 에서 도 한 파일 의 내용 을 문자열 에 읽 으 려 면 fileget_contents (), fread 보다 성능 이 훨씬 좋 습 니 다.https://www.php.net/manual/zh/function.fread.php
file 함수 도 할 수 있 습 니 다. 원 하 는 결 과 는 여기 서 프 리 젠 테 이 션 을 하지 않 습 니 다.file 함 수 는 하나의 파일 을 하나의 배열 에 읽 는 것 입 니 다.사실 위의 세 함수 의 원 리 는 모두 같다. 바로 큰 파일 을 한꺼번에 메모리 에 읽 는 것 이다. 분명히 이런 방식 은 메모 리 를 소모 하고 큰 파일 을 처리 할 때 이 방법 은 바람 직 하지 않다.
우 리 는 이론의 두 번 째 방법 을 다시 보고 단락 을 나 누 어 읽 었 다.이 방법 은 하나의 큰 문 서 를 몇 개의 작은 단락 으로 나 누 어 매번 한 단락 의 분석 을 읽 고 마지막 에 통합 시 켜 통 계 를 분석 하 는 것 이다.fgets 는 매번 한 줄 을 읽 는데, 마치 우리 가 원 하 는 것 같다.
string fgets ( resource $handle [, int $length ] )

첫 번 째 매개 변 수 는 파일 시스템 포인터 입 니 다. fopen 에서 만 들 고 돌아 오 는 값 입 니 다. 두 번 째 매개 변 수 는 읽 을 크기 입 니 다.length 가 지정 되 지 않 으 면 기본 값 은 1K 또는 1024 바이트 이 며, 값 을 정확하게 읽 은 내용 으로 되 돌려 줍 니 다.
지금 위의 코드 를 다시 한 번 수정 하 세 요.다음 과 같다.
";
    echo "   fgets:    :" . ($em - $sm) . "
"; } writeLogC();

실행 한 후에 메모리 가 많이 떨 어 진 것 을 발 견 했 지만 시간 은 여전히 같은 것 같 았 다.실행 결 과 는 다음 과 같 습 니 다.
왜 그 랬 을 까? 사실은 간단 하 다. 지금 은 한 줄 씩 메모리 에 읽 을 때마다 메모리 가 높 지 않 기 때문이다.그러나 어쨌든 상기 세 가지 방법 은 전체 파일 (10 만 줄) 을 한 번 순환 해 야 하기 때문에 시간 이 지나 면 세 가지 방법 은 크게 다 르 지 않다.그럼 더 좋 은 방법 없 을까요?다 중 스 레 드 를 사용 하여 큰 파일 을 작은 파일 로 나 누고 모든 스 레 드 에서 작은 파일 을 처리 하 는 것 입 니 다. 그러면 시간 이 많이 줄 어 들 것 입 니 다.
PHP 는 기본적으로 다 중 스 레 드 모듈 이 설치 되 어 있 지 않 습 니 다. 스스로 설치 해 야 합 니 다.설치 되 어 있 지 않 습 니 다. 확인 하 십시오. https://www.yduba.com/biancheng-6852262344.html
지금 위의 방법 에 따라 코드 를 다음 과 같은 방법 으로 바 꿉 니 다.
i = $i;
    }

    public function run()
    {
	$filename = "temp_log_" . Thread::getCurrentThreadId();
	$cutline = ($this->i - 1) * 40000 + 1 . ", " . ($this->i * 40000);
	exec("sed -n '" . $cutline . "p' " . READ_FILE . " > " . $filename);

	$this->_writeTemp( $filename );
    }

    private function _writeTemp( $readfile = '' )
    {
	if( !$readfile || !file_exists($readfile) ) return;

    	$fileres  = fopen($readfile, 'r');
	$writeres = fopen(WRITE_FILE_D, 'a+');

	//    WRITE_FILE
	flock($writeres, LOCK_EX);

	while( $row = fgets($fileres) )
	{
	    if( strpos($row, "[error]") !== false )
	    {
	        fwrite($writeres, $row);
	    }
	}

	flock($writeres, LOCK_UN);
	fclose($fileres);
	fclose($writeres);
	unlink( $readfile );
    }
}

function writeLogd()
{
    $st = microtime( true );
    $sm = memory_get_usage();

    $count_line = 0;

    //         
    $content 		= exec('wc -l ' . READ_FILE);
    $content_arr 	= explode(" ", $content);
    $count_line 	= $content_arr[0];

    //   
    $count_thread 	= ceil($count_line / 40000);

    $worker = array();
    for($i=1; $i<=$count_thread; $i++)
    {
    	$worker[$i] = new Mythread( $i );
    	$worker[$i]->start();
    }
    $em = memory_get_usage();
    $et = microtime( true );
    echo "      :    :" . ($et - $st) . "
";     echo "   :  :" . ($em - $sm) . "
"; } writeLogd();

운행 해 보 니 시간 이 수직 으로 떨 어 지 는 것 을 발견 했다.메모리 도 줄 었 다.실행 결과 그림:
 
특히 스 레 드 수가 많 을 수록 좋 은 것 은 아니다.스 레 드 수량 이 많 으 면 모든 스 레 드 에서 처리 하 는 시간 이 적 습 니 다. 그러나 스 레 드 를 만 들 때 도 시간 을 낭비 합 니 다. 저 는 여기 서 스 레 드 마다 4 만 개의 기록 을 처리 합 니 다. 이 수 를 줄 이거 나 증가 시 켜 결 과 를 테스트 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기