Pisałem apkę do wczytywania dużych plików XML i JSON do bazy i mam pewien problem
mam 2 pliki jeden z tymi samymi danymi i do wczytywania XML używam
https://github.com/prewk/xml-string-streamer
a Json
https://github.com/pcrov/JsonReader
i okazuje się, że wczytywanie Json trwa x100 wolniej ;(
sprawdzałem xdebug profilerem (o ile to dobrze zrobiłem) to za wolne działanie odpowiada ta class JsonReader.
Mój kod. Co robię nie tak ;(
$stream = http://www.php.net/fopen($file->getRealPath(), "rb"); $reader = new JsonReader(); $reader->stream($stream); /* * Wczytywanie obiektu * $record - pojedyńczy record najwyższego poziomu w json * $tree - przechowuje zagnieżdżenie elementu w strukturze, indeksy poszczególnych rekordów. * $tmp - tablica do której zapisujemy dany poziom struktury rekordu json * $depth - level na którym sa itemy; */ $record = []; $tree = []; $tmp = &$record; $depth = 1; /* * Wczytywanie elementów json, zakonczyć gdy otrzymamy pełny jeden wpis. * $record ma mieć formę tablicy asocjacyjnej. */ while ($reader->read()) { switch ($reader->type()) { /* * Początek obiektu lub tablicy */ case JsonReader::OBJECT : case JsonReader::http://www.php.net/array : /* * Jeżeli mamy pusty index to okręślamy go na podstawie ostatniego zapisanego elementu w $tree */ if ($reader->depth() > $depth) { if (http://www.php.net/empty($reader->name())) { $tree[] = ($c = http://www.php.net/count($tmp) > 0) ? $c : 0; $tmp = &$tmp[http://www.php.net/end($tree)]; } else { $tree[] = $reader->name(); $tmp = &$tmp[$reader->name()]; } $tmp = []; } break; /* * Koniec obiektu lub tablicy */ case JsonReader::END_OBJECT : case JsonReader::END_ARRAY : /* * Jeżeli obiekt lub tablica się zakończyli musimy wrócić do wcześniejszego * elementu w strukturze */ if ($reader->depth() > $depth) { $tmp = &$record; if (http://www.php.net/count($tree) > 0) { http://www.php.net/array_pop($tree); foreach ($tree as $item) { $tmp = &$tmp[$item]; } } } elseif ($reader->depth() == $depth) { dump($tmp); $record = []; $tmp = &$record; } break; /* * Pojedynczy element */ default : /* * Jeżeli indeks jest pusty (np. ["a", 1, "b", 2]) * dodajemy element przez array_push * w przeciwnym razie * dołączamy nowy wpis przez array_merge */ if ($reader->depth() > $depth) { if (http://www.php.net/empty($reader->name())) { http://www.php.net/array_push($tmp, $reader->value()); } else { $tmp = http://www.php.net/array_merge($tmp, [$reader->name() => $reader->value()]); } } } } $reader->close(); http://www.php.net/fclose($stream);
Ja używałem swego czasu tego: https://github.com/MAXakaWIZARD/JsonCollectionParser
Ze 160 MB sobie radził.
Tutaj niestety wychodzi porównanie wydajności pomiędzy kodem napisanym w C + PHP (wbudowany moduł od obsługi XML w C wykorzystywany przez API w PHP) konta czyste PHP. Co tu dużo mówić, PHP jest wolny. Co możesz zrobić?
1. Upewnij się, że korzystasz z PHP 7.x nie 5.x - jest zauważalnie szybszy, ale na pewno nie zniweluje Ci to różnicy.
2. Poszukaj jakiegoś prasera, który został napisany jako moduł w C dla PHP. Wtedy powinieneś uzyskać czasy takie jak w przypadku XML-a. Przy czym nie mam pojęcia czy takowy istnieje.
3. To już jest obejście, nie rozwiązanie problemu:
3.a. Przy pomocy zewnętrznego, wydajnego softu konwertuj sobie JSON do XML przed przetworzeniem.
3.b. W ogóle skorzystaj z innej platformy.
Powyższa biblioteka daje lepsze czasy, ale moim zdaniem nie jesteś w stanie zejść poniżej paru sekund w czystym php. Rozwiązaniem porównywalnym do tego z XML jest albo odpalenie parserów w pytonie albo doinstalowanie specjalnych bibliotek do Apacha. Tego ostatniego nie próbowałem, ale jak szukałem dla siebie rozwiązań, było kilka polecanych z rok temu, które ponoć dawały dobre wyniki.
Dziekuję za pomoc. Myślałem, że takie wyniki nie są akceptowalne, ale skoro to norma to lecimy dalej ...
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)