Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Wydajność w pętlach vs. iteratorach

Aby zdecydować, czy użyć pętli, czy iteratorów, musisz wiedzieć, która implementacja jest szybsza: wersja funkcji search z jawną pętlą for czy wersja z iteratorami.

Przeprowadziliśmy benchmark, ładując całą zawartość Przygód Sherlocka Holmesa Sir Arthura Conana Doyle’a do String i szukając słowa the w zawartości. Oto wyniki benchmarku dla wersji search używającej pętli for i wersji używającej iteratorów:

test bench_search_for  ... bench:  19,620,300 ns/iter (+/- 915,700)
test bench_search_iter ... bench:  19,234,900 ns/iter (+/- 657,200)

Obie implementacje mają podobną wydajność! Nie będziemy tutaj wyjaśniać kodu benchmarku, ponieważ nie chodzi o udowodnienie, że obie wersje są równoważne, ale o ogólne rozeznanie, jak te dwie implementacje wypadają pod względem wydajności.

Aby uzyskać bardziej kompleksowy benchmark, powinieneś sprawdzić użycie różnych tekstów o różnych rozmiarach jako contents, różnych słów i słów o różnej długości jako query oraz wszelkiego rodzaju innych wariacji. Chodzi o to: iteratory, choć są abstrakcją wysokiego poziomu, są kompilowane do mniej więcej tego samego kodu, co gdybyś sam napisał kod niższego poziomu. Iteratory to jedna z abstrakcji zerokosztowych Rusta, co oznacza, że użycie abstrakcji nie narzuca żadnego dodatkowego narzutu czasowego. Jest to analogiczne do tego, jak Bjarne Stroustrup, oryginalny projektant i implementator C++, definiuje zerowy narzut w swoim przemówieniu inauguracyjnym ETAPS z 2012 roku „Foundations of C++”:

Ogólnie rzecz biorąc, implementacje C++ przestrzegają zasady zerowego narzutu: Czego nie używasz, za to nie płacisz. A dalej: Czego używasz, nie mógłbyś napisać ręcznie lepiej.

W wielu przypadkach kod Rusta używający iteratorów kompiluje się do tego samego assemblera, co kod napisany ręcznie. Stosowane są optymalizacje, takie jak rozwinięcie pętli i eliminacja sprawdzania zakresów przy dostępie do tablic, co sprawia, że wynikowy kod jest niezwykle wydajny. Teraz, gdy to wiesz, możesz bez obaw używać iteratorów i domknięć! Sprawiają, że kod wydaje się być na wyższym poziomie, ale nie narzucają kary za wydajność w czasie działania.

Podsumowanie

Domknięcia i iteratory to cechy Rusta inspirowane ideami programowania funkcyjnego. Przyczyniają się one do zdolności Rusta do wyraźnego wyrażania idei wysokiego poziomu z niskopoziomową wydajnością. Implementacje domknięć i iteratorów są takie, że wydajność w czasie działania nie jest naruszana. Jest to część celu Rusta, jakim jest dążenie do zapewnienia abstrakcji zerokosztowych.

Teraz, gdy ulepszyliśmy ekspresywność naszego projektu I/O, przyjrzyjmy się kilku innym funkcjom cargo, które pomogą nam udostępnić projekt światu.