No dobra, dzisiaj muszę pobrać ze dane ze strony. Uzywam #symfony2 i #goutte Mam już wszystko gotowe, skrypt działa i w ogóle. Problem jest taki że strona ma ogromną ilość podstron. Np
Lista elementów: |- Lista obiektów: |- spis |- spis |- spis |- Lista obiektów: |- spis |- spis |- spis |- Lista obiektów: |- spis |- spis |- spis więc wychodzi tego naprawdę dużo. Problem mam taki że na początku skrypt w miarę fajnie leci, i ETA wychodzi około 2h. Ale po 20 minuach wzrazta już do 3h a po kolejnych do 7 i tak dalej..
Zrobiłem taki myk:
$em = $this->getContainer()->get('doctrine')->getEntityManager(); $em->getConnection()->getConfiguration()->setSQLLogger(null); Ale niewiele to dało... Przez przeglądarkę strona mi się odpala od strzału, nie ma żadnej zadyszki ani nic... tylko skrypt zwalnia.. Na końcu pętli mam persisty i flush Co jeszcze mogę zrobić? Dodam że skrypt jest napisany w #symfony2 pod konsolą (command).
@qwelukasz: Generalnie powinieneś pakować to w paczki (po powiedzmy 50 obiektów jeśli jeszcze tego nie robisz), a po flushu warto przeiterować po tych obiektach i zrobić na nich
$entityManager->detach($object); Wtedy Garbage Collector będzie mógł od razu je zgarnąć i posprzątać, w innym przypadku siedzą w pamięci niepotrzebne obiekty.
edit: ewentualnie po flushu zrób $em->clear(); który #!$%@? wszystkie obiekty w EM
@qwelukasz: robić flusha i clear co 50 iterację, kodu nie chce mi się pisać w tym momencie, więc musisz sam sobie poradzić, co do opcache musisz go włączyć w konfiguracji PHP, a nie apki. Env prod na końcu w takiej postaci jak Ci napisałem
@qwelukasz: na devie system zbiera bardzo dużo informacji przydatnych do debugowania i za każdym razem przeładowuje konfiguracje, której nie #!$%@?. Zrób również php app/console cache:warmup --env=prod przed wykonaniem komendy. Znacznie przyspiesza całość aplikacji.
@qwelukasz: Tak się tego nie robi, uruchom sobie skrypt równolegle i zobacz jak zmienia się ETA. Jeżeli rozdzielisz to na osobne zadania razem z jakaś kolejka, to pozbędziesz się obecnych problemów a dodatkowo przyspieszysz pobieranie treści.
Poniżej masz kawałek przykładowego kodziku w jaki sposób możesz uniknąć ładowania danych do arraya i iterowania później po tym. Tablice w PHP zjadają bardzo dużo pamięci, dopiero w PHP 7 będzie to znacznie zoptymalizowane. Ciężko mi się wypowiedzieć bo nie widzę tego co masz napisane. W każdym razie powyciągane (nie wiem skąd) obiekty ładujesz sobie do kolekcji, a jak już masz wszystko to robisz sobie
foreach($objectCollection->getIterator() as $object) { $em->persist($object);
@hajs86: ok załóżmy taki bardzo prosty przykład: co w przypadku gdy mam np. ManyToOne i obiekty: Dzień, TypDnia $d1 = new TypDnia(); $d1->setName('Poniedzialek');
$d2 = new TypDnia(); $d2->setName('Wtorek');
$arr[1] = $d1; $arr[2] = $d2; I teraz iteruję dni miesiąca i chę wiedzieć jaki to dzień?
foreach($objectCollection->getIterator() as $object) { echo $arr[ $Dzien->getDayNumber() ]->getName(); } W takim przypadku muszę encje TypDnia trzymać w tablicy, chyba że zrobię kolejną pętlę i będę
@qwelukasz: Nie bardzo łapię o co teraz ci chodzi. Masz problem z wydajnością skryptu. Z pewnością w PHP iterowanie po dużych arrayach nie należy do najwydajniejszych dlatego przedstawiłem ci szybszą opjcę z wykorzystaniem SplObjectStorage i generatora dostępnego od PHP 5.5. Popisz sobie różne opcje i sam wyciągaj wnioski, w googlach też sporo na ten temat znajdziesz. Tutaj się raczej nie dogadamy.
@hajs86: hmm, no o może inaczej. Jeżeli mam kolekcję. Jak mogę z niej pobrać konkretny obiekt z pominięciem foreach? Załóżmy że mam obiekt Miasto oraz obiekt NazwaMiasta
Obiekt Miasto posiada ID z NazwaMiasta. W przypadku tablic zrobiłbym to tak:
$nazwy['1'] = $katowice; $nazwy['2'] = $warszawa;
I wtedy z obiektu Miasto mogę się tak odwołać: $id = Miasto->getIdMiasta
$nazwy[ $id ] da mi nazwę miasta.. a w przypadku kolekcji?
@qwelukasz: Ten kodzik który ci wyslałem opiera się o SplObjectStorage. Poczytaj sobie jak to działa http://php.net/manual/en/class.splobjectstorage.php, Do funkcji attach możesz przekazać 2 parametry, gdzie pierwszy będzie kluczem a drugi obiektem który chcesz zapisać. Potem możesz do tego się odwołać jak do tablicy bo SplObjectStorage implementuje interfejs ArrayAccess albo przez metodę offsetGet
Zaplusuj jeśli nie pobrałeś karty do referendum. Głosowałem chwilę po 7 rano i podobnie jak ja udziału w referendum odmówiła co druga osoba :) #polska #wybory #wydarzenia #chwalesie
No dobra, dzisiaj muszę pobrać ze dane ze strony. Uzywam #symfony2 i #goutte
Mam już wszystko gotowe, skrypt działa i w ogóle. Problem jest taki że strona ma ogromną ilość podstron.
Np
Lista elementów:
|- Lista obiektów:
|- spis
|- spis
|- spis
|- Lista obiektów:
|- spis
|- spis
|- spis
|- Lista obiektów:
|- spis
|- spis
|- spis
więc wychodzi tego naprawdę dużo. Problem mam taki że na początku skrypt w miarę fajnie leci, i ETA wychodzi około 2h. Ale po 20 minuach wzrazta już do 3h a po kolejnych do 7 i tak dalej..
Zrobiłem taki myk:
$em = $this->getContainer()->get('doctrine')->getEntityManager();
$em->getConnection()->getConfiguration()->setSQLLogger(null);
Ale niewiele to dało... Przez przeglądarkę strona mi się odpala od strzału, nie ma żadnej zadyszki ani nic... tylko skrypt zwalnia..
Na końcu pętli mam
persist
y iflush
Co jeszcze mogę zrobić?
Dodam że skrypt jest napisany w #symfony2 pod konsolą (command).
$entityManager->detach($object);
Wtedy Garbage Collector będzie mógł od razu je zgarnąć i posprzątać, w innym przypadku siedzą w pamięci niepotrzebne obiekty.
edit: ewentualnie po flushu zrób $em->clear(); który #!$%@? wszystkie obiekty w EM
@DanioPL: ale gdzie to odpalic? Swój skrypt odpalam tak:
php app/console nazwa:metoda parametr
. Na końcu mam dodać-e prod
?A obiekty to tak:
Dwa dodaję na początku, tzn robię
persist
.A potem w pętli 5x persist i na końcu pętli flush. I tak przy każdej iteracji.
@DanioPL: Nie.
Dodać do config.yml ten wpis?
doctrine:
orm:
...
metadata_cache_driver: apc
...
php app/console cache:warmup --env=prod
przed wykonaniem komendy. Znacznie przyspiesza całość aplikacji.Tak jak koledzy wyżej pisali, wykorzystaj funkcję detach() i clear(), dodatkowo po zapisaniu możesz robić unset($obj)
Obecnie mam tablicę obiektów i odwołuję się w niej tak:
foreach( range( 0, count($arr) as $num ) {
$arr[$num] <- mój obiekt
}
Poniżej masz kawałek przykładowego kodziku w jaki sposób możesz uniknąć ładowania danych do arraya i iterowania później po tym. Tablice w PHP zjadają bardzo dużo pamięci, dopiero w PHP 7 będzie to znacznie zoptymalizowane. Ciężko mi się wypowiedzieć bo nie widzę tego co masz napisane. W każdym razie powyciągane (nie wiem skąd) obiekty ładujesz sobie do kolekcji, a jak już masz wszystko to robisz sobie
foreach($objectCollection->getIterator() as $object)
{
$em->persist($object);
co w przypadku gdy mam np.
ManyToOne
i obiekty:Dzień
,TypDnia
$d1 = new TypDnia();
$d1->setName('Poniedzialek');
$d2 = new TypDnia();
$d2->setName('Wtorek');
$arr[1] = $d1;
$arr[2] = $d2;
I teraz iteruję dni miesiąca i chę wiedzieć jaki to dzień?
foreach($objectCollection->getIterator() as $object)
{
echo $arr[ $Dzien->getDayNumber() ]->getName();
}
W takim przypadku muszę encje TypDnia trzymać w tablicy, chyba że zrobię kolejną pętlę i będę
Jeżeli mam kolekcję. Jak mogę z niej pobrać konkretny obiekt z pominięciem foreach?
Załóżmy że mam obiekt Miasto oraz obiekt NazwaMiasta
Obiekt Miasto posiada ID z NazwaMiasta.
W przypadku tablic zrobiłbym to tak:
$nazwy['1'] = $katowice;
$nazwy['2'] = $warszawa;
I wtedy z obiektu Miasto mogę się tak odwołać:
$id = Miasto->getIdMiasta
$nazwy[ $id ]
da mi nazwę miasta.. a w przypadku kolekcji?