Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Stream to files - jakby to przyśpieszyć?
Forti
post
Post #1





Grupa: Zarejestrowani
Postów: 655
Pomógł: 73
Dołączył: 2.05.2014

Ostrzeżenie: (0%)
-----


Cześć!

Przejde do rzeczy. Mamy tablice, w ten sposób:

  1. $data = [
  2. 0 => [ // 70 tyś. rekordów
  3. 0 => [] // tutaj średnio 5-6 rekordów,
  4. // i tak dalej
  5. ],
  6. 1 => [],
  7. 2 => [],
  8. // i tak dalej.
  9. ];


Ogólnie takich małych tablic po 5-6 rekordów jest ok. 8mln. Podzielone są po 70 tyś. Teraz te 70 tyś. zapisuje w postaci .csv:

  1. foreach ($this->result as $fileNumber => $data) {
  2. $stream = fopen('php://memory', 'w');
  3.  
  4. foreach ($data as $line) {
  5. fputcsv($stream, $line, $this->config['delimiter']);
  6. }
  7. fseek($stream, 0);
  8. $content = stream_get_contents($stream);
  9. $content = str_replace('"', '', $content); // potrzeba usuwania ", w żadnym innym miejscu tego zrobić nie mogę, a iterować po całej tablicy i robić na mniejszych stringach to bezsensu moim zdaniem... jak myślicie?
  10.  
  11. $now = new \DateTime('now');
  12. $fileName = $fileName . $now->format('Y-m-d-h-i-s') . "_{$fileNumber}_" . '.csv';
  13.  
  14. $file = fopen(__DIR__ . '/../../parsed/' . $fileName, "w");
  15. fputs($file, $content);
  16. fclose($file);
  17. }



Teraz sedno sprawy:

Przy 100k rekordów trwa to dosłownie kilka sekund. Przy 1mln trwa to już średnio 3 minuty (ostatnia próba: 223 sekundy) (licze z pomocą microtime(true)). Nawet boje się włączyć na 8mln rekordów...
Jakiś pomysł jak to przyśpieszyć? Cel: zapis do pliku .csv.

Ten post edytował Forti 7.08.2015, 09:57:19
Go to the top of the page
+Quote Post
pyro
post
Post #2





Grupa: Zarejestrowani
Postów: 2 148
Pomógł: 230
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Jeśli chodzi o ten myk z cudzysłowem, to nie szkodzi. Miałem parę razy podobny problem i niestety mniej więcej tak się go rozwiązuje, więc jest to OK.

Jeśli chodzi o sam czas, to najprawdopodobniej to przez to, że ładujesz wszystkie dane do pamięci, przez co maszyna jest tak obciążona, że wszystko działa dużo wolniej.

Jeśli pobierasz dane z bazy, to rób to jakimś data provider iteratorem i pobieraj w segmentach.
Go to the top of the page
+Quote Post
Forti
post
Post #3





Grupa: Zarejestrowani
Postów: 655
Pomógł: 73
Dołączył: 2.05.2014

Ostrzeżenie: (0%)
-----


Nie stety, ale dane są najpierw pobierane w kilku plików (każdy po 1mln), parsowane odpowiednio i zapisywane. Cały proces od kilku dni optymalizuje jak tylko się da.
Go to the top of the page
+Quote Post
CuteOne
post
Post #4





Grupa: Zarejestrowani
Postów: 2 958
Pomógł: 574
Dołączył: 23.09.2008
Skąd: wiesz, że tu jestem?

Ostrzeżenie: (0%)
-----


Nie bardzo rozumiem po co ci ten stream, przecież niżej otwierasz plik i wrzucasz do niego dane z bazy. Jak dla mnie podwójna robota.. coś w ten deseń
  1. $now = new \DateTime;
  2. foreach ($this->result as $fileNumber => $data) {
  3. $fileName = $fileName . $now->format('Y-m-d-h-i-s') . "_{$fileNumber}_" . '.csv';
  4. $stream = fopen(__DIR__ . '/../../parsed/' . $fileName, "w");
  5.  
  6. fputcsv($stream, $data, $this->config['delimiter']);
  7. fclose($file);
  8. }


@edit: upitoliłem foreacha, trzeba go przywrócić (IMG:style_emoticons/default/wink.gif)

Ten post edytował CuteOne 7.08.2015, 10:11:24
Go to the top of the page
+Quote Post
pyro
post
Post #5





Grupa: Zarejestrowani
Postów: 2 148
Pomógł: 230
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Cytat(Forti @ 7.08.2015, 11:08:13 ) *
Nie stety, ale dane są najpierw pobierane w kilku plików (każdy po 1mln), parsowane odpowiednio i zapisywane. Cały proces od kilku dni optymalizuje jak tylko się da.


No to musisz bardziej doprecyzować co to znaczy "odpowiednio parsowane i zapisywane".

Cytat(CuteOne @ 7.08.2015, 11:08:42 ) *
Nie bardzo rozumiem po co ci ten stream, przecież niżej otwierasz plik i wrzucasz do niego dane z bazy. Jak dla mnie podwójna robota.. coś w ten deseń
  1. $now = new \DateTime;
  2. foreach ($this->result as $fileNumber => $data) {
  3. $fileName = $fileName . $now->format('Y-m-d-h-i-s') . "_{$fileNumber}_" . '.csv';
  4. $stream = fopen(__DIR__ . '/../../parsed/' . $fileName, "w");
  5.  
  6. fputcsv($stream, $data, $this->config['delimiter']);
  7. fclose($file);
  8. }


Wczytaj się jeszcze raz w to co ten kod robi.
Go to the top of the page
+Quote Post
Forti
post
Post #6





Grupa: Zarejestrowani
Postów: 655
Pomógł: 73
Dołączył: 2.05.2014

Ostrzeżenie: (0%)
-----


Z tym parsowaniem to nie istotne, po prostu pobieram zawartość z plików (zmienne), obrabiam i dopasowuje w odpowiednie zmienne. Słowa kluczowe itp.
Ogólnie całość i tak ląduje w takiej tablicy i nie bardzo mam jak inaczej to zrobić.

Jeżeli nie ma innego sposobu a tak dużą tablice zapisać w .csv w szybszy sposób, to będzie musiało to tak zostać..

Ten post edytował Forti 7.08.2015, 10:19:35
Go to the top of the page
+Quote Post
pyro
post
Post #7





Grupa: Zarejestrowani
Postów: 2 148
Pomógł: 230
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Cytat(Forti @ 7.08.2015, 11:14:38 ) *
londuje


(IMG:https://s-media-cache-ak0.pinimg.com/236x/0c/f5/19/0cf519769a6212d46d7a8e333c1849ea.jpg)

Cytat(Forti @ 7.08.2015, 11:14:38 ) *
Z tym parsowaniem to nie istotne, po prostu pobieram zawartość z plików (zmienne), obrabiam i dopasowuje w odpowiednie zmienne. Słowa kluczowe itp.
Ogólnie całość i tak londuje w takiej tablicy i nie bardzo mam jak inaczej to zrobić.

Jeżeli nie ma innego sposobu a tak dużą tablice zapisać w .csv w szybszy sposób, to będzie musiało to tak zostać..


Czyli jednak źle robisz. Pobieraj z tych plików w mniejszych segmentach i obrabiaj tak samo.
Go to the top of the page
+Quote Post
Forti
post
Post #8





Grupa: Zarejestrowani
Postów: 655
Pomógł: 73
Dołączył: 2.05.2014

Ostrzeżenie: (0%)
-----


*ląduje lol skąd to sie tam wzięło (IMG:style_emoticons/default/biggrin.gif)

Właśnie tak zrobiłem, zamiast przekazywać wszystkie pliki - pobierać wawartość, mergować ją, obrabiać i zapisywać to pobieram liste plików i z każdego osobna. W teorii powinienem zyskać średnio 2-3 minuty na każde 1mln rekordów. Zobaczymy jak wyjdzie.
Go to the top of the page
+Quote Post
pyro
post
Post #9





Grupa: Zarejestrowani
Postów: 2 148
Pomógł: 230
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Raczej chodziło mi o to, żebyś mniejszymi segmentami pobierał i parsował, tj. pamięć jest zapchana tylko tyle, ile ma dany segment, a nie mniejszymi segmentami pobierać, żeby je wszystkie najpierw wrzucić i tak do pamięci, a dopiero później operować (IMG:style_emoticons/default/biggrin.gif)
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 22.08.2025 - 22:06