CSV를 다룰때 단순하게 작업을 하게 되면, 메모리부족으로 Allowed memory size of라는 문구를 볼수 있습니다.

 

PHP의 디폴트 메모리는 128MB로 되어있으며, 넘길 경우 'Allowed memory size of'가 됩니다,

그래서 메모리 사용량을 줄이기위해 사용하는 것 중 하나가 Generator입니다.

 

물론, 다른방법도 존재하고 있습니다.

  1. php.ini파일에서 memory_limit의 메모리를 늘리기
  2. 코드에 ini_set('memory_limit','512M') 를 사용하여 임시적으로 메모리 제한을 늘리기
제너레이터란

공식홈페이지의 내용 (https://www.php.net/manual/en/language.generators.syntax.php)

제너레이터 함수란, 겉보기엔 일반함수와 거의 같습니다.

다른점은 모든 값을 반환하는것이 아니라, 필요한 만큼의 값을 yield를 이용하여 반환 하는 것 입니다.

제너레이터 함수가 불려지면, 반복처리가 가능한 오브젝트를 반환합니다.

오브젝트가 (foreach나while등등)로 반복되면 값이 필요할 때마다 제너레이터 함수를 부릅니다. 그리고 제너레이터값이 yield 된 시점의 상태를 보존해 두고, 다음 값이 필요할때가 됬을때 그 보존 해준 다음 값부터 처리 됩니다.

yield가능한 값이 없어지면 제너레이터함수는 종료됩니다.

 

간단한 사용법

yield는 예제처럼 forearch를 이용하여 사용합니다.
return의 경우는 함수당 한번만 값을 반환하지만 yield의 경우는 필요할 때마다 언제나 값을 반환 할수 있습니다.

function test() {
    for ($i = 1; $i <= 3; $i++) {
        // for이 반복될때마다 $i의값도 같이 반환합니다.
        yield $i;
    }
}

foreach ($this->test() as $value) {
    echo "$value\n";
}
// 결과값
// 1
// 2
// 3

 

메모리 사용량

일반 배열과 제너레터의 메모리 사용량에 대해 알아보겠습니다.

 

셋팅

// 일반 배열 
public function arrayTest() 
{
  $data = [];
  $this->getMemoryUsage();
  for ($i=0; $i<2000000; $i++) {
    $data[] = $i;
  }
  $this->getMemoryUsage();
  return $data;
}

// 제너레이터
public function generatorTest()
{
  $this->getMemoryUsage();
  for ($i=0; $i<2000000; $i++) {
    yield $i;
  }
  $this->getMemoryUsage();
}

public function getMemoryUsage()
{
    print("Memory = ".round(memory_get_usage() / (1024*1024), 1)." MB");
}

 

결과

// 시작:10.2MB
// 종료:74.2MB 
foreach ($this->arrayTest() as $item => $value) {
  // 처리작업
}

// 시작:10.2MB
// 종료:10.2MB 
foreach ($this->generatorTest() as $item => $value) {
  // 처리작업
}

배열의 경우가 제너레이터보다 훨씬 많은 메모리를 사용하고 있는것을 알수 있었습니다.

 

 

CSV등 많은 데이터를 다루는 경우에는 제너레이터를 이용한 작업을 할때 이용하면 큰 도움이 됩니다.!

+ Recent posts