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ść)
Odpowiedz
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?
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
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! –
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?
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 –
"Factor of few" to mój nowy termin techniczny mówiący z personelem nietechnicznym o tym, dlaczego powinniśmy przejść na Python. – BlackVegetable
[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
@jdero Oznacza to, że zasadniczo zachowuje się identycznie jak w Javie, prawda? – BlackVegetable