2012-07-09 13 views
19

Ich habe einen Symfony-Befehl geschrieben, um einige Daten von einer API zu importieren. Es funktioniert, aber das Problem ist, dass meine PHP-Speicherauslastung zunimmt, wenn ich einen großen JSON in meine Datenbank einfüge. Und mein UnitOfWork erhöht sich nach jedem Aktivitätsimport um '2'.

Ich habe bereits ungesetzt all meine verwendeten Objekte, und ich habe die Dokumentation von Symfony2 lesen, wenn Sie massive Partie tun: http://www.doctrine-project.org/blog/doctrine2-batch-processing.html

Aber wenn ich $em->clear() Manager meiner Einheit verwenden gibt diesen Fehler:

Notice: Undefined index: 000000007b56ea7100000000e366c259 in path-to-application\vendor\doctrine\lib\Doctrine\ORM\UnitOfWork.php line 2228

Hier

ist mein kompletter Code:

/** 
* @see Command 
*/ 
protected function configure() { 
    $this 
    ->setName('ks:user:runkeepersync') 
    ->setDescription('Synchroniser les activités d\'un utilisateur runkeeper') 
    ->setDefinition(array(
     new InputArgument('access_token', InputArgument::REQUIRED, 'Access token'), 
    )) 
} 

/** 
* @see Command 
*/ 
protected function execute(InputInterface $input, OutputInterface $output) { 
    $accessToken = $input->getArgument('access_token'); 
    $em = $this->getContainer()->get('doctrine')->getEntityManager(); 
    $UserHasServices = $em->getRepository('KsUserBundle:UserHasServices')->findOneByToken($accessToken); 
    if (!is_object($UserHasServices)) { 
    echo "Impossible de trouver l'utilisateur qui possède le jeton ".$accessToken.""; 
    } 
    $user = $UserHasServices->getUser(); 
    $service = $UserHasServices->getService(); 
    echo "avant de requérir l'api : ".memory_get_usage()."\n"; 
    try { 
    $rkApi = $this->getContainer()->get('ks_user.runkeeper'); 
    $rkApi->setAccessToken($accessToken); 
    $activities = $rkApi->getFitnessActivities(0,25); 
    $nbParPages = 25; 
    $nomberActivitites = $activities->size; 
    $aActivities = $activities->items; 
    $nbPages = floor ($nomberActivitites/$nbParPages); 
    $aEndurance = array("Running", "Cycling", "Mountain Biking", "Walking", "Hiking", "Downhill Skiing", "Cross-Country Skiing", "Snowboarding", "Skating","Wheelchair", "Rowing", "Elliptical", "Other"); 
    $aEnduranceUnderWater = array("Swimming"); 
    $enduranceOnEarthType = $em->getRepository('KsActivityBundle:SportType')->findOneByLabel("endurance"); 
    if (!is_object($enduranceOnEarthType)) { 
     echo "Impossible de trouver le type de sport d'endurance"; 
    } 
    $enduranceUnderWaterType = $em->getRepository('KsActivityBundle:SportType')->findOneByLabel("endurance_under_water"); 
    if (!is_object($enduranceUnderWaterType)) { 
     echo "Impossible de trouver le type de sport d'endurance sous l'eau "; 
    } 
    echo "Après avoir récupéré 25 activités : ".memory_get_usage()."\n"; 
    $a = 0; 
    for($i=0;$i<=$nbPages;$i++){ 
     if($i!=0){ 
     $activities = $rkApi->getFitnessActivities($i,25); 
     $aActivities = $activities->items; 
     } 
     foreach ($aActivities as $activity) { 
     $a = $a+1; 
     $codeSport = $this->formatNameSport($activity->type); 
     $sport = $em->getRepository('KsActivityBundle:Sport')->findOneByCodeSport($codeSport); 
     if (!is_object($sport)) { 
      $sport = new \Ks\ActivityBundle\Entity\Sport(); 
      $sport->setLabel($codeSport); 
      $sport->setCodeSport($codeSport); 
      $sport->setSportType($enduranceOnEarthType); 
      $em->persist($sport); 
      $em->flush(); 
     } 
     $activityDetail = json_decode($rkApi->requestJSONHealthGraph($activity->uri)); 
     if(in_array($activity->type, $aEndurance)){ 
      $urlActivitieDetail = $activityDetail->activity; 
      $ActivitySessionEnduranceOnEarth = new \Ks\ActivityBundle\Entity\ActivitySessionEnduranceOnEarth($user); 
      isset($activity->total_distance)? $ActivitySessionEnduranceOnEarth->setDistance($activity->total_distance) : ""; 
      isset($activity->duration)? $ActivitySessionEnduranceOnEarth->setDuration($this->secondesToTimeDuration($activity->duration)) : ""; 
      isset($activity->start_time)? $ActivitySessionEnduranceOnEarth->setIssuedAt(new \DateTime($activity->start_time)) : ""; 
      $ActivitySessionEnduranceOnEarth->setModifiedAt(new \DateTime('Now')); 
      $ActivitySessionEnduranceOnEarth->setSport($sport); 
      isset($activityDetail->total_calories)? $ActivitySessionEnduranceOnEarth->setCalories($activityDetail->total_calories) : ""; 
      isset($activityDetail->climb)? $ActivitySessionEnduranceOnEarth->setElevationGain($activityDetail->climb) : ""; 
      $maxElevation = 0; 
      $minElevation = 10000; 
      if(isset($activityDetail->path)){ 
      foreach($activityDetail->path as $gpsPoint){ 
       if($gpsPoint->altitude > $maxElevation){ 
       $maxElevation = $gpsPoint->altitude; 
       } 
       if($gpsPoint->altitude < $minElevation){ 
       $minElevation = $gpsPoint->altitude; 
       } 
      } 
      $ActivitySessionEnduranceOnEarth->setElevationMin($minElevation); 
      $ActivitySessionEnduranceOnEarth->setElevationMax($maxElevation); 
      } 
      $em->persist($ActivitySessionEnduranceOnEarth); 
      $em->flush(); 
      //Pour chaque activité on a un identifiant relatif au service qu'on synchronise 
      $ActivityComeFromService = new \Ks\ActivityBundle\Entity\ActivityComeFromService(); 
      $ActivityComeFromService->setActivity($ActivitySessionEnduranceOnEarth); 
      $ActivityComeFromService->setService($service); 
      $ActivityComeFromService->setIdWebsiteActivityService($activity->uri); 
      $ActivityComeFromService->setSourceDetailsActivity($rkApi->requestJSONHealthGraph($activity->uri)); 
      $ActivityComeFromService->setTypeSource("JSON"); 
      $em->persist($ActivityComeFromService); 
      $em->flush(); 
      echo "Import de l'activite num ".$a." type :".$activity->type." effectue avec success \n"; 
      unset($ActivitySessionEnduranceOnEarth); 
      unset($ActivityComeFromService); 
      echo "UnitOFWOrk -> ".$em->getUnitOfWork()->size()."\n"; 
     } 
     if(in_array($activity->type, $aEnduranceUnderWater)){ 
      $ActivitySessionEnduranceUnderWater = new \Ks\ActivityBundle\Entity\ActivitySessionEnduranceUnderWater($user); 
      isset($activity->total_distance)? $ActivitySessionEnduranceUnderWater->setDistance($activity->total_distance) : ""; 
      isset($activity->duration)? $ActivitySessionEnduranceUnderWater->setDuration($this->secondesToTimeDuration($activity->duration)) : ""; 
      isset($activity->start_time) && !empty($activity->start_time)? $ActivitySessionEnduranceUnderWater->setIssuedAt(new \DateTime($activity->start_time)) : ""; 
      $ActivitySessionEnduranceUnderWater->setModifiedAt(new \DateTime('Now')); 
      $ActivitySessionEnduranceUnderWater->setSport($sport); 
      isset($activityDetail->total_calories)? $ActivitySessionEnduranceUnderWater->setCalories($activityDetail->total_calories) : ""; 
      isset($activityDetail->notes)? $ActivitySessionEnduranceUnderWater->setDescription($activityDetail->notes) : ""; 
      $em->persist($ActivitySessionEnduranceUnderWater); 
      $em->flush(); 
      $ActivityComeFromService = new \Ks\ActivityBundle\Entity\ActivityComeFromService(); 
      $ActivityComeFromService->setActivity($ActivitySessionEnduranceUnderWater); 
      $ActivityComeFromService->setService($service); 
      $ActivityComeFromService->setIdWebsiteActivityService($activity->uri); 
      $ActivityComeFromService->setSourceDetailsActivity($rkApi->requestJSONHealthGraph($activity->uri)); 
      $ActivityComeFromService->setTypeSource("JSON"); 
      $em->persist($ActivityComeFromService); 
      $em->flush(); 
      echo "Import de l'activité num ".$a." type :".$activity->type." effectué avec succès\n"; 
      unset($ActivitySessionEnduranceUnderWater); 
      unset($ActivityComeFromService); 
     } 
     echo "Après chaque activité : ".memory_get_usage()."\n"; 
     unset($sport); 
     unset($activityDetail); 
     $em->clear(); 
     } 
    } 
    } catch (\Exception $e) { 
    throw $e; 
    } 
} 

Danke, @AdrienBrault. Ich habe mit --env=prod --no-debug getestet, und es ist wahr, dass es weniger Speicher verbraucht, aber der Speicher noch erhöht. Wie kann ich den Entity Manager wirklich löschen? und stabilisieren Sie die Erinnerung?

+0

Der erste Schritt Speicherauslastung auf Befehle zu verringern, ist sie auf der prod-Umgebung ausgeführt werden und mit Debug deaktiviert: 'PHP app/console command --env = prod --no-debug' – AdrienBrault

+1

Dank , @AdrienBrault Ich habe mit --env = prod --no-debug getestet, und es ist wahr, dass es weniger Speicher verbraucht, aber der Speicher steigt immer noch ... Wie kann ich tun, um den Entity Manager wirklich zu löschen? und stabilisieren Sie die Erinnerung? – psylo66

+0

@Hosh, warum nicht einen Kommentar unter der Antwort hinzufügen, die Sie nicht mögen, erklären, warum es keine gute Lösung ist? Sie sind möglicherweise bereit, weitere Hilfe oder Rat anzubieten. – halfer

Antwort

1

Versuchen Sie, den Entity Manager zurück:

$this->getContainer()->get('doctrine')->resetEntityManager(); 

und dann:

$em = $this->getContainer()->get('doctrine')->getEntityManager(); 
8

Symfony alle SQL-Abfragen in dev Umgebung protokolliert, so zuerst Sie es deaktivieren müssen

// disable logger 
$em->getConnection()->getConfiguration()->setSQLLogger(null); 

Sie können Ereignis-Listener für Entitäten verwenden, dies kann auch die Speicherbelegung erhöhen. Sie können sie wie deaktivieren, so

// remove all listeners 
foreach ($em->getEventManager()->getListeners() as $event => $listeners) { 
    foreach ($listeners as $listener) { 
     $em->getEventManager()->removeEventListener($event, $listener); 
    } 
} 

entfernen unset aus dem Code, gibt es keine Notwendigkeit für sie, wie Sie klar Manager Einheit bei jedem Schritt der Schleife.

// save and clear 
$em->flush(); 
$em->getUnitOfWork()->clear(); 

diese Lehre Denken Sie daran, Ihre Anfragen optimieren und Perfomance zu verbessern, wenn Sie Gruppe in eine flush abfragt. Die beste Vorgehensweise wäre also, einmal über einige Teile Ihrer Daten flush auszuführen. Zum Beispiel:

// collect 100 entities and then save them 
if (($i % 100) == 0) { 
    $em->flush(); 
    $em->getUnitOfWork()->clear(); 
} 
+0

Das ist nicht genau die Lösung. Aber deine Lösung hat mich zur Lösung geführt. Es stellt sich heraus, dass einer der Ereignis-Listener, die ich überschrieb (indem ich den Klassenparameter dafür überlastete) etwas tat, das dies verursachte. Das Entfernen dieser Definition (und das manuelle Entfernen dieses Ereignis-Listeners) löste dieses Problem.Ich werde dir die Belohnung geben. –

+0

Wie hast du den "undefinierten Index" losgeworden? Und können Sie Code für die erweiterte Lösung schreiben, über die Sie gesprochen haben? –

Verwandte Themen