Wady lenistwa?

Ostatnio zacząłem używać Lazy w całej mojej aplikacji i zastanawiałem się, czy są jakieś oczywiste negatywne aspekty, które muszę wziąć pod uwagę przy użyciu Lazy<T>?

Staram się wykorzystywać Lazy<T> tak często, jak uważam to za stosowne, przede wszystkim w celu zmniejszenia śladu pamięci naszych załadowanych, ale nieaktywnych wtyczek.

 48
Author: eandersson, 2011-09-27

7 answers

Rozbuduję nieco mój komentarz, który brzmi:

Właśnie zacząłem używać Lazy, i okazało się, że jest to często orientacyjne złego projektu; lub lenistwa ze strony programisty. Ponadto jeden wadą jest to, że trzeba być bardziej czujnym z scoped up zmiennych, i stworzyć odpowiednie zamknięcia.

Na przykład, użyłem Lazy<T> do tworzenia stron, które użytkownik może zobaczyć w mojej (sessionless) aplikacji MVC. To kreator prowadzący, więc użytkownik może chcieć przejść do losowy poprzedni krok. Gdy zostanie wykonany uścisk dłoni, tablica obiektów {[2] } zostanie zamknięta, a jeśli użytkownik określi jako krok, ta dokładna strona zostanie oceniona. Uważam, że zapewnia dobrą wydajność, ale są pewne aspekty, które mi się nie podobają, na przykład wiele moich foreach konstrukcji wygląda teraz tak:

foreach(var something in somethings){
     var somethingClosure = something;
     list.Add(new Lazy<Page>(() => new Page(somethingClosure));
} 

Tzn. musisz bardzo aktywnie radzić sobie z problemem zamykania. W przeciwnym razie nie sądzę, że to taki zły hit wydajności, aby przechowywać lambda i ocenić go, gdy potrzebne.

Z drugiej strony może to wskazywać na to, że programista jest Lazy<Programmer>, w tym sensie, że wolałbyś nie myśleć teraz o swoim programie, a zamiast tego pozwolić właściwej logice ocenić, gdy jest to potrzebne , jak w moim przypadku-zamiast budować tę tablicę, mogłem po prostu dowiedzieć się, jaka byłaby ta konkretna żądana strona; ale wybrałem lenistwo i podejście all in.

EDIT

Przyszło mi do głowy, że Lazy<T> ma też kilka osobliwości podczas pracy z współbieżnością. Na przykład istnieje ThreadLocal<T> dla niektórych scenariuszy i kilka konfiguracji flag dla konkretnego scenariusza wielowątkowego. Możesz przeczytać więcej na msdn.

 19
Author: Gleno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-27 10:36:28

Moim zdaniem zawsze powinieneś mieć powód do wyboru leniwego. Istnieje kilka alternatyw w zależności od przypadku użycia i są zdecydowanie przypadki, w których ta struktura jest odpowiednia. Ale nie używaj go tylko dlatego, że jest fajny.

Na przykład nie rozumiem sensu w przykładzie wyboru strony w jednej z innych odpowiedzi. Korzystanie z listy leniwych do wyboru pojedynczego elementu może być dobrze zrobione z listą lub słownikiem delegatów bezpośrednio bez użycia leniwych lub z prostym switch statement.

Więc najbardziej oczywistymi alternatywami są

  • bezpośrednia instancja dla tanich struktur danych lub struktur, które i tak są potrzebne
  • delegatów dla rzeczy, które są potrzebne od zera do kilku razy w jakimś algorytmie
  • pewna struktura buforowania dla elementów, które powinny zwolnić pamięć, gdy nie są używane przez jakiś czas
  • pewnego rodzaju" przyszłościowa " struktura jak zadanie, które już może rozpocząć inicjalizację asynchronicznie przed rzeczywistym użyciem zużywającym bezczynny CPU czas w przypadkach, gdy prawdopodobieństwo jest dość wysokie, że struktura będzie wymagana później

W przeciwieństwie do tego, lenistwo jest często odpowiednie, gdy

  • obliczeniowo intensywne struktury danych
  • są potrzebne od zera do wiele razy w jakimś algorytmie, gdzie przypadek zerowy ma duże prawdopodobieństwo
  • i dane są lokalne dla jakiejś metody lub klasy i mogą być zbierane jako śmieci, gdy nie są już używane lub dane powinny być przechowywane w pamięci dla całego programu runtime
 9
Author: CSharper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-20 22:51:55

Tutaj nie do końca negatywny aspekt, ale gotcha dla leniwych:).

Leniwe inicjalizatory są jak statyczne inicjalizatory. Uciekają raz . Jeśli wyjątek jest wyrzucany, wyjątek jest buforowany, a kolejne wywołania do .Wartość rzuci ten sam wyjątek. Jest to projektowane i jest wymienione w dokumentach ... http://msdn.microsoft.com/en-us/library/dd642329.aspx :

Wyjątki rzucane przez valueFactory są buforowane.

Stąd kod jak poniżej nigdy nie zwróci wartości:

bool firstTime = true;
Lazy<int> lazyInt = new Lazy<int>(() =>
{
    if (firstTime)
    {
        firstTime = false;
        throw new Exception("Always throws exception the very first time.");
    }

    return 21;
});

int? val = null;
while (val == null)
{
    try
    {
        val = lazyInt.Value;
    }
    catch
    {

    }
}
 7
Author: Thilak Nathen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-18 03:13:59

Zacząłem używać Lazy<T> głównie ze względu na możliwości współbieżności podczas ładowania zasobów z bazy danych. W ten sposób pozbyłem się przedmiotów blokujących i wątpliwych wzorów blokujących. W moim przypadku ConcurrentDictionary + Lazy jako wartość uczynił mój dzień, dzięki @Reed Copsey i jego blog post

Wygląda to następująco. Zamiast wołania:

MyValue value = dictionary.GetOrAdd(
                             key, 
                             () => new MyValue(key));

Zamiast tego użylibyśmy ConcurrentDictionary>, a napisz:

MyValue value = dictionary.GetOrAdd(
                             key, 
                             () => new Lazy<MyValue>(
                                 () => new MyValue(key)))
                          .Value;

Brak minusów Lazy<T> zauważyłem więc daleko.

 5
Author: Max Yakimets,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-21 10:25:31

Jak w przypadku czegokolwiek, Lazy<T> może być używany dla dobra lub dla zła, stąd wada: gdy jest używany niewłaściwie, może powodować zamieszanie i frustrację. Jednak leniwy wzór inicjalizacji istnieje od lat, a teraz, gdy. NET BCL ma implementację deweloperzy nie muszą ponownie odkrywać koła. Co więcej, MEF kocha lenistwo .

 4
Author: Anton Gogolev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-27 10:17:04

Co dokładnie masz na myśli przez "w całym moim zgłoszeniu"?

Myślę, że powinien być używany tylko wtedy, gdy nie jesteś pewien, czy wartość zostanie użyta, co może mieć miejsce tylko w przypadku opcjonalnych parametrów, które zajmują dużo czasu, aby obliczyć. Może to obejmować złożone obliczenia, obsługę plików, Usługi internetowe, dostęp do bazy danych i tak dalej.

Z drugiej strony, po co używać Lazy tutaj? W większości przypadków można po prostu wywołać metodę zamiast lazy.Value i to nie robi różnicy w każdym razie. Ale jest to prostsze i bardziej oczywiste dla programisty, co dzieje się w tej sytuacji bez Lazy.

Jedną oczywistą zaletą może być już zaimplementowane buforowanie wartości, ale nie sądzę, że jest to tak duża zaleta.

 2
Author: Simon Woker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-27 10:20:40

Lazy jest używany do zachowania zasobów, gdy nie są one naprawdę potrzebne. Ten wzór jest całkiem dobry, ale implementacja może być bezużyteczna.

Większy zasób jest, użyteczny jest ten wzór.

Zakaz używania klasy Lazy jest zakazem użycia. W rzeczy samej, trzeba wszędzie utrzymać dodatkową indrection (.Wartość). Kiedy potrzebujesz tylko wystąpienia prawdziwego typu, jest on zmuszony do załadowania, nawet jeśli nie musisz go używać bezpośrednio.

Lazy is for lazy zyskuje produktywność, ale zysk ten może zostać utracony przez wysokie zużycie.

Jeśli masz prawdziwą transparentną implementację (używając wzorca proxy dla exemple), pozbądź się dezawantacji i w wielu przypadkach może to być bardzo przydatne.

Współbieżność musi być brana pod uwagę w innym aspekcie, a nie zaimplementowana domyślnie w twoim typie. Musi być zawarty tylko w kodzie klienta lub helperach typu dla tej koncepcji.

 2
Author: Teter28,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-08 17:51:29