2017-01-30 28 views
6

Uruchomiłem kod, którego część ładuje się w dużej szufladzie 1D z pliku binarnego, a następnie zmienia tablicę za pomocą metody numpy.where().Python losowo spada do 0% użycia procesora, powodując, że kod "zawiesza się", podczas obsługi dużych tablic numpy?

Oto przykład z operacji wykonywanych w kodzie:

import numpy as np 
num = 2048 
threshold = 0.5 

with open(file, 'rb') as f: 
    arr = np.fromfile(f, dtype=np.float32, count=num**3) 
    arr *= threshold 

arr = np.where(arr >= 1.0, 1.0, arr) 
vol_avg = np.sum(arr)/(num**3) 

# both arr and vol_avg needed later 

Mam biegać to wiele razy (na wolnym komputerze, to znaczy żadna inna hamowanie CPU lub pamięć użycie) bez problemu. Ale ostatnio zauważyłem, że czasami kod zawiesza się na dłuższy czas, dzięki czemu środowisko wykonawcze jest o rząd wielkości dłuższe. Przy tych okazjach monitorowałem użycie procentu procesora i pamięci (przy użyciu monitora systemu gnome) i stwierdziłem, że użycie procesora Pythona spada do 0%.

Używanie podstawowych wydruków pomiędzy powyższymi operacjami do debugowania, wydaje się być dowolne, która operacja powoduje wstrzymanie (tj. Open(), np.fromfile(), np.where() kazdy osobno spowodował zawieszenie w losowym przebiegu). To tak, jakbym był dławiony losowo, ponieważ na innych biegach nie ma zawieszania.

Rozważałem takie rzeczy jak zbieranie śmieci lub this question, ale nie widzę żadnego oczywistego związku z moim problemem (na przykład naciśnięcia klawiszy nie mają żadnego efektu).

Dalsze uwagi: plik binarny ma 32 GB, a urządzenie (z systemem Linux) ma pamięć 256 GB. Używam tego kodu zdalnie, poprzez sesję ssh.

EDYCJA: Może to być przypadek, ale zauważyłem, że nie ma żadnych rozłączeń, jeśli uruchomię kod po ponownym uruchomieniu komputera. Wygląda na to, że zaczynają się dziać po kilku uruchomieniach lub co najmniej innym korzystaniu z systemu.

+0

Naprawdę nie sądzę, że tak jest, ale czy monitor gnome sys monitoruje wątek zamiast procesu? Wierzę, że numpy widzi nowy wątek do ciężkich obliczeń, ale powinien znajdować się w tej samej grupie procesów. wtedy znowu mogę być całkowicie w błędzie – Aaron

+0

Z tego powodu użycie pamięci nie jest problemem, czy czasami możesz wyświetlać stronicowanie, gdy pyton się zawiesza? Czy Twój "plik" znajduje się na dysku lokalnym na komputerze, z którego korzystasz, czy jest dostępny za pomocą NFS lub podobnego? Sieć I/O może być winowajcą, a spowolnienia mogą pojawiać się losowo w zależności od tego, co robią inni użytkownicy. – wildwilhelm

+0

@wildwilhelm Plik nie jest przechowywany na dysku lokalnym komputera, więc być może jest to problem z siecią I/O. Będę robić kolejne przebiegi i monitorować wysyłanie/pobieranie sieciowe, aby sprawdzić, czy istnieje korelacja! – Lewis

Odpowiedz

0

Spadek użycia procesora nie był związany z pythonem lub numpy, ale w rzeczywistości był wynikiem odczytu z udostępnionego dysku, a sieć I/O była prawdziwym winowajcą. Dla tak dużych tablic odczytanie w pamięci może być poważnym wąskim gardłem.

1

np.where tworzy tam kopię i przypisuje ją ponownie do arr. Tak więc, możemy zoptymalizować pamięci nie unikając krok do kopiowania, jak tak -

vol_avg = (np.sum(arr) - (arr[arr >= 1.0] - 1.0).sum())/(num**3) 

używamy boolean-indexing aby wybrać elementy, które są większe niż 1.0 i coraz ich odsunięcia od 1.0 i zsumowanie tych i odjęcie od całkowita suma. Mam nadzieję, że liczba takich przekroczeń elementów jest mniejsza i jako taka nie będzie więcej wymagać pamięci. Zakładam, że ten problem zawieszania się z dużymi tablicami jest oparty na pamięci.

+0

myślisz, że malloc powoduje tymczasowe zawieszenie w systemie operacyjnym? – Aaron

+0

@Aaron Nie jest pewien, czy pamięć jest jedynym winowajcą, ale mając nadzieję, że pamięć jest problemem, powinno to zmniejszyć zapotrzebowanie na pamięć tego problemu, zwłaszcza, że ​​OP wspomniał, że dzieje się to z dużymi tablicami. – Divakar

+0

Czy jesteś pewien, że coś zapisujesz? Myślę, że 'arr> = 1.0', a następnie' arr [arr> = 1.0] ', a następnie' arr [arr> = 1.0] - 1.0' spowoduje, że każdy z nich będzie tworzył nowe tablice, pierwszy z bajtów, a następnie podzbiór oryginalna tablica, a następnie zmutowana kopia oryginalnej tablicy. Gdy wyrażenie zakończy się, wszystkie zostaną oczyszczone, ale wyrażenie filtru będzie zajmowało mniej więcej jedną czwartą pamięci RAM oryginalnej macierzy, a dwa półprodukty będą zajmować dane proporcjonalne do liczby wartości, które przeszły przez filtr. Kod OP podwaja wymaganą pamięć (krótko), ale ma stały koszt. – ShadowRanger