2013-07-26 12 views
12

Ostatnio używałem pythona coraz częściej zamiast c/C++, ponieważ skraca on mój czas kodowania o kilka razy. W tym samym czasie, gdy przetwarzam duże ilości danych, szybkość, z jaką działają moje programy Pythona, zaczyna być znacznie wolniejsza niż w c. Zastanawiam się, czy to ze względu na mnie nieefektywne korzystanie z dużych obiektów/tablic. Czy jest jakiś wyczerpujący przewodnik po tym, jak pamięć jest obsługiwana przez numpy/python? Kiedy rzeczy są przekazywane przez odniesienie i kiedy według wartości, kiedy rzeczy są kopiowane, a kiedy nie, jakie typy są zmienne, a które nie.Python numpy i wydajność pamięci (przekazywanie przez odniesienie vs. wartość)

+9

"Factor of few" to mój nowy termin techniczny mówiący z personelem nietechnicznym o tym, dlaczego powinniśmy przejść na Python. – BlackVegetable

+4

[Ten post] (http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference) ma bogobojną ilość odpowiednich danych na to pytanie ... – jdero

+0

@jdero Oznacza to, że zasadniczo zachowuje się identycznie jak w Javie, prawda? – BlackVegetable

Odpowiedz

1

więc będę musiał zacytować EOL na to, bo myślę, że jego odpowiedź jest bardzo istotne:

3) Ostatni punkt jest związany z tytułu pytanie: „przechodząc przez wartości” oraz "przekazywanie przez odniesienie" nie są pojęciami, które są istotne w pythonie . Odpowiednie pojęcia są zamiast tego "obiektem zmiennym" i "niezmiennym obiektem" . Listy są zmienne, a numery nie, co wyjaśnia, co obserwujesz. Ponadto obiekty Person1 i bar1 są zmienne (dlatego można zmienić wiek danej osoby). Więcej informacji na temat tych pojęć można znaleźć w samouczku tekstowym i samouczku wideo o nazwie . Wikipedia ma również pewne (bardziej techniczne) informacje. przykład ilustruje różnicę między zachowaniem zmienny i niezmienny - answer by EOL

Generalnie mam znaleźć Numpy/scipy śledzić te; co ważniejsze, mówią ci wyraźnie w dokumentach, co się dzieje.

Na przykład np.random.shuffle prosi o tablicę wejściową i zwraca None, a np.random.permutation zwraca tablicę. Możesz wyraźnie zobaczyć, który z nich zwraca wartość, a nie tutaj.

Podobna liczba tablic ma semantykę typu "przejdz? Referencje" i ogólnie uważam, że Numpy/Scipy jest bardzo wydajna.

Myślę, że to uczciwie powiedzieć, że jeśli będzie szybciej używać pass-by-reference, będą. Dopóki używasz funkcji w sposób, w jaki mówią doktorzy, nie powinieneś mieć znaczących problemów z szybkością.


Czy istnieje jakiś konkretny typ, o który pytasz?

+0

Dzięki za odpowiedź. Nie, nie ma naprawdę konkretnych typów, które rozważałem; Bardziej szukałem odpowiedzi na ogólne, optymalne style kodowania, które można zastosować do wydajności obliczeniowej. Myślę, że to może nie istnieć dla Pythona, poza zaufaniem, że metody numpy/scipy są już zoptymalizowane. – DilithiumMatrix

+0

Niestety w ogóle python został stworzony dla łatwości, a nie prędkości :). Można jednak pisać części, które mają być "szybkie" w C, i wywoływać je w Pythonie, aby uzyskać szybkie środowisko wykonawcze, lub zawsze jak się mówi, numpy/scipy.Również kompilacja numpy/scipy dla konkretnej kompilacji może pomóc zoptymalizować je dalej! –

8

Obiekty w języku Python (i większość popularnych języków) są przekazywane jako referencje.

Jeśli np. Przyjmujemy numpy, to "nowe" tablice tworzone przez indeksowanie istniejących są tylko widokami oryginału. Na przykład:

import numpy as np 

>>> vec_1 = np.array([range(10)]) 
>>> vec_1 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
>>> vec_2 = vec_1[3:] # let vec_2 be vec_1 from the third element untill the end 
>>> vec_2 
array([3, 4, 5, 6, 7, 8, 9]) 
>>> vec_2[3] = 10000 
array([3, 4, 5, 10000, 7, 8, 9]) 
>>> vec_1 
array([0, 1, 2, 3, 4, 5, 10000, 7, 8, 9]) 

Numpy mieć poręczny sposób, aby pomóc z pytaniami o nazwie may_share_memory (obj1, obj2). Więc:

>>> np.may_share_memory(vec_1, vec_2) 
True 

Podobnie należy zachować ostrożność, ponieważ `s możliwe metody, aby powrócić fałszywych alarmów (chociaż nigdy nie widział jeden).

Na SciPy 2013 był samouczek dotyczący numpy (http://conference.scipy.org/scipy2013/tutorial_detail.php?id=100). Na koniec facet mówi trochę o tym, jak numpy obsługuje pamięć. Obejrzyj to.

Zgodnie z ogólną zasadą, obiekty prawie nigdy nie są przekazywane jako wartość domyślnie. Nawet te zamknięte na innym obiekcie. Inny przykład, w którym lista tworzy trasę:

Class SomeClass(): 

    def __init__(a_list): 
     self.inside_list = a_list 

    def get_list(self): 
     return self.inside_list 

>>> original_list = range(5) 
>>> original_list 
[0,1,2,3,4] 
>>> my_object = SomeClass(original_list) 
>>> output_list = my_object.get_list() 
>>> output_list 
[0,1,2,3,4] 
>>> output_list[4] = 10000 
>>> output_list 
[0,1,2,3,10000] 
>>> my_object.original_list 
[0,1,2,3,10000] 
>>> original_list 
[0,1,2,3,10000] 

Creepy, huh? Używając symbolu przypisania ("=") lub zwracając go na końcu funkcji, zawsze utworzysz wskaźnik do obiektu lub jego części. Obiekty są duplikowane tylko wtedy, gdy wyraźnie to robisz:, używając metody kopiowania, np. Some_dict.copy lub array [:]. Na przykład:

>>> original_list = range(5) 
>>> original_list 
[0,1,2,3,4] 
>>> my_object = SomeClass(original_list[:]) 
>>> output_list = my_object.get_list() 
>>> output_list 
[0,1,2,3,4] 
>>> output_list[4] = 10000 
>>> output_list 
[0,1,2,3,10000] 
>>> my_object.original_list 
[0,1,2,3,10000] 
>>> original_list 
[0,1,2,3,4] 

Masz?

+0

Myślę, że w twoim ostatnim przykładzie 'my_object.original_list' powinno być' my_object.get_list() '. Również możesz chcieć dodać, jak 'vec2 [:]' zachowuje się w porównaniu do 'vec2', gdy wartość jest do nich przypisana w twoim pierwszym przykładzie –