W przypadku kodu, w którym należy wykonać czyszczenie zasobu przed wyjściem z funkcji, istnieje znaczna różnica w wydajności między tymi 2 sposobami wykonania tego.
Czyszczenie zasobu przed każdym zwrotem
void func() { login(); bool ret = dosomething(); if(ret == false) { logout(); return; } ret = dosomethingelse(); if(ret == false) { logout(); return; } dootherstuff(); logout(); }
Czyszczenie zasobu w końcu bloku
void func() { login(); try { bool ret = dosomething(); if(ret == false) return; ret = dosomethingelse(); if(ret == false) return; dootherstuff(); } finally { logout(); } }
Zrobiłem kilka podstawowych testów w przykładowych programach i wydaje się, że nie ma dużej różnicy. Tak bardzo wolę finally
sposób na zrobienie tego - ale zastanawiałem się, czy to wpłynie na wydajność w dużym projekcie.
java
performance
efficiency
użytkownik93353
źródło
źródło
if(!cond)
, to java mnie do tego zmusiła. W C ++ w ten sposób piszę kod zarówno logiczne, jak i dla innych typów - tjint x;
if(!x)
. Ponieważ java pozwala mi używać tego tylko dobooleans
, całkowicie przestałem używaćif(cond)
&if(!cond)
in java.(someIntValue != 0)
niż porównywać niż oceniać booleany. To mi pachnie i przerabiam to natychmiast, gdy widzę to na wolności.Odpowiedzi:
Jak wskazano w Jak powolne są wyjątki Java? widać, że powolność
try {} catch {}
mieści się w obrębie samego wyjątku.Utworzenie wyjątku spowoduje pobranie całego stosu wywołań z środowiska wykonawczego i to tam jest koszt. Jeżeli nie tworzysz wyjątek, to tylko bardzo niewielkie zwiększenie czasu.
W przykładzie podanym w tym pytaniu nie ma żadnych wyjątków, nie można oczekiwać spowolnienia ich tworzenia - nie są tworzone. Zamiast tego chodzi tutaj o
try {} finally {}
obsługę dezalokacji zasobów w bloku wreszcie.Tak więc, aby odpowiedzieć na pytanie, nie, nie ma rzeczywistych wydatków na środowisko uruchomieniowe w
try {} finally {}
strukturze, która nie używa wyjątków (nie jest to niespotykane, jak widać). Co jest ewentualnie drogie jest utrzymanie czasu, gdy jeden odczytuje kod i widzi to nie typowy styl kodu i koder musi uzyskać ich umysł dookoła, że coś innego się dzieje w tej metodzie od wyprodukowaniareturn
przed powrotem do poprzedniej rozmowy.Jak już wspomniano, utrzymanie jest argumentem na oba sposoby osiągnięcia tego celu. Dla przypomnienia, moim wyborem byłoby podejście ostateczne.
Zastanów się, jaki czas poświęcić na nauczenie kogoś nowej struktury językowej. Widzenie
try {} finally {}
nie jest czymś, co często widuje się w kodzie Java i dlatego może być mylące dla ludzi. Na naukę nieco bardziej zaawansowanych struktur w Javie jest pewien czas konserwacji, niż ludzie znają.finally {}
Blok zawsze działa. I dlatego powinieneś go użyć. Weź również pod uwagę czas konserwacji debugowania podejścia, które nie jest ostateczne, gdy ktoś zapomni o wylogowaniu w odpowiednim czasie lub zadzwoni o nim w niewłaściwym czasie, lub zapomni o powrocie / wyjściu po wywołaniu, aby wywołać go dwukrotnie. Istnieje tak wiele możliwych błędów, że użycietry {} finally {}
uniemożliwia ich użycie .Ważenie tych dwóch kosztów jest kosztowne w czasie konserwacji, aby nie stosować tego
try {} finally {}
podejścia. Chociaż ludzie mogą zastanawiać się, ile ułamków milisekund lub dodatkowych instrukcji JVMtry {} finally {}
blok jest porównywany z inną wersją, należy również wziąć pod uwagę godziny spędzone na debugowaniu mniej niż idealnego sposobu rozwiązania problemu dezalokacji zasobów.Najpierw napisz utrzymywalny kod, najlepiej w taki sposób, aby uniknąć późniejszego napisania błędów.
źródło
/programming/299068/how-slow-are-java-exceptions
Przyjęta odpowiedź na to pytanie pokazuje, że zawinięcie wywołania funkcji w bloku try catch kosztuje mniej niż 5% w porównaniu z samym wywołaniem funkcji. Faktyczne zgłoszenie i wyłapanie wyjątku spowodowało, że środowisko wykonawcze wygenerowało balon ponad 66-krotnie w stosunku do samego wywołania funkcji. Jeśli więc spodziewasz się, że projekt wyjątku będzie regularnie zgłaszany, to spróbuję go ominąć (w odpowiednio wyprofilowanym kodzie krytycznym pod względem wydajności), jednak jeśli wyjątkowa sytuacja jest rzadka, nie jest to wielka sprawa.
źródło
Zamiast optymalizacji - pomyśl o tym, co robi Twój kod.
Dodanie wreszcie bloku jest inną implementacją - oznacza to, że wylogujesz się przy każdym wyjątku.
W szczególności - jeśli logowanie zgłosi wyjątek, zachowanie w drugiej funkcji będzie inne niż pierwsze.
Jeśli logowanie i wylogowanie nie są częścią zachowania funkcji, sugerowałbym, że metoda powinna zrobić jedną rzecz dobrze:
i powinien być w funkcji, która jest już zamknięta w kontekście, który zarządza logowaniem / wylogowaniem, ponieważ wydają się one zasadniczo różnić od tego, co robi główny kod.
Twój post jest oznaczony jako Java, którego nie znam zbyt dobrze, ale w .net użyłbym do tego bloku używającego:
to znaczy:
Kontekst logowania ma metodę Dispose, która wyloguje się i wyczyści zasoby.
Edycja: Właściwie nie odpowiedziałem na pytanie!
Nie mam żadnych wymiernych dowodów, ale nie spodziewałbym się, że będzie to droższe lub z pewnością niewystarczająco drogie, aby było warte przedwczesnej optymalizacji.
Pozostawiam resztę odpowiedzi, ponieważ chociaż nie odpowiadam na pytanie, myślę, że jest to pomocne dla PO.
źródło
using
konstrukcji .net , zakładając, że dany zasób implementujeAutoCloseable
interfejs.ret
zmienną, która jest właśnie przypisana dwukrotnie, aby sprawdzić jedną linię później. Zrób toif (dosomething() == false) return;
.ret2 = doSomethingElse(ret1)
, ale to nie dotyczy pytania, więc zostało usunięte.if (dosomething() == false) ...
jest zły kod. Użyj bardziej inaktywnegoif (!dosomething()) ...
Założenie: rozwijasz się w kodzie C #.
Szybka odpowiedź jest taka, że nie ma znaczącego spadku wydajności przy użyciu bloków try / last. Występuje uderzenie wydajności, gdy rzucasz wyjątkami.
Dłuższą odpowiedzią jest przekonanie się. Jeśli spojrzysz na wygenerowany kod CIL ( np. Reflektor z czerwoną bramką) , zobaczysz wygenerowane instrukcje CIL i zobaczysz w ten sposób wpływ.
źródło
Jak inni już wspomniano, kod Ttese mają różne wyniki, jeśli jedna
dosomethingelse
lubdootherstuff
wyjątek.I tak, każde wywołanie funkcji może zgłosić wyjątek, przynajmniej
StackOVerflowError
! Chociaż rzadko jest możliwe prawidłowe ich obsługiwanie (ponieważ jakakolwiek wywoływana funkcja czyszczenia prawdopodobnie będzie miała ten sam problem, w niektórych przypadkach (takich jak na przykład wdrażanie blokad) ważne jest, aby nawet poprawnie to obsłużyć ...źródło