przekazywanie przez in
odniesienie wydaje się logicznie równoważne przekazywaniu przez wartość.
Poprawny.
Czy jest jakaś przewaga wydajności?
Tak.
Wierzyłem, że po stronie zaplecza ref
parametr musi przynajmniej kopiować fizyczny adres zmiennej, który powinien mieć taki sam rozmiar jak każde typowe odniesienie do obiektu.
Nie ma wymogu, aby odwołanie do obiektu i odniesienie do zmiennej miały ten sam rozmiar, i nie ma wymogu, aby każdy z nich był wielkością słowa maszynowego, ale tak, w praktyce oba mają 32 bity na 32 maszyny bitowe i 64-bitowe na maszynach 64-bitowych.
Jak myślisz, co ma z tym wspólnego „adres fizyczny”, nie jest dla mnie jasne. W systemie Windows używamy adresów wirtualnych , a nie adresów fizycznych w kodzie trybu użytkownika. Ciekaw jestem, w jakich możliwych okolicznościach możesz sobie wyobrazić, że adres fizyczny ma znaczenie w programie C #.
Nie ma również wymogu implementacji jakiegokolwiek odniesienia jako adresu wirtualnego magazynu. Odwołania mogą być nieprzezroczystymi uchwytami do tabel GC w zgodnej implementacji specyfikacji CLI.
czy zaletą jest tylko w przypadku większych konstrukcji?
Motywującym scenariuszem dla tej funkcji jest obniżenie kosztu przekazywania większych konstrukcji.
Zwróć uwagę, że nie ma gwarancji, in
że program będzie faktycznie szybszy i może spowalniać programy. Na wszystkie pytania dotyczące wydajności muszą odpowiedzieć badania empiryczne . Istnieje bardzo niewiele optymalizacji, które zawsze przynoszą korzyści ; nie jest to optymalizacja typu „zawsze wygrywająca”.
czy jest jakaś zakulisowa optymalizacja kompilatora, która czyni go atrakcyjnym gdzie indziej?
Kompilator i środowisko uruchomieniowe mogą dokonywać dowolnej optymalizacji, którą wybiorą, jeśli nie narusza to reguł specyfikacji języka C #. O in
ile mi wiadomo, nie ma jeszcze takiej optymalizacji parametrów, ale to nie wyklucza takich optymalizacji w przyszłości.
dlaczego nie powinienem uczynić każdego parametru in?
Załóżmy, że int
zamiast parametru utworzyłeś in int
parametr. Jakie koszty są nakładane?
- witryna wywołania wymaga teraz zmiennej, a nie wartości
- zmienna nie może zostać zarejestrowana. Starannie dostrojony schemat alokacji rejestrów jittera właśnie został wrzucony do niego kluczem.
- kod w miejscu wywołania jest większy, ponieważ musi pobierać odwołanie do zmiennej i umieścić go na stosie, podczas gdy wcześniej mógł po prostu umieścić wartość na stosie wywołań
- większy kod oznacza, że niektóre instrukcje krótkiego skoku mogły teraz stać się instrukcjami skoku w dal, więc znowu kod jest teraz większy. Ma to efekt domina na różne rzeczy. Pamięci podręczne zapełniają się wcześniej, jitter ma więcej do zrobienia, jitter może zdecydować się nie wykonywać pewnych optymalizacji dla większych rozmiarów kodu i tak dalej.
- w witrynie wywoływanej zmieniliśmy dostęp do wartości na stosie (lub rejestrze) w pośredni wskaźnik. Prawdopodobnie ten wskaźnik znajduje się w pamięci podręcznej, ale nadal zmieniliśmy dostęp do wartości z jedną instrukcją w dostęp z dwiema instrukcjami.
- I tak dalej.
Załóżmy, że to a double
i zmienisz go na in double
. Ponownie, teraz zmienna nie może zostać zarejestrowana w wysokowydajnym rejestrze zmiennoprzecinkowym. Ma to wpływ nie tylko na wydajność , ale może również zmienić zachowanie programu! C # może wykonywać arytmetykę zmiennoprzecinkową z dokładnością wyższą niż 64-bitowa i zazwyczaj robi to tylko wtedy, gdy można zarejestrować zmiennoprzecinkowe.
To nie jest darmowa optymalizacja. Musisz porównać jego wydajność z alternatywami. Najlepiej jest po prostu nie tworzyć dużych konstrukcji, jak sugerują wytyczne projektowe.
ref
służy do przekazywania struktur przez odwołanie zamiast ich kopiowania.in
oznacza, że struktura nie powinna być modyfikowana.