Niespodziewanie, znajdę startswith
jest wolniejszy niż in
:Dlaczego łańcuchy zaczynają wolniej niż w?
In [10]: s="ABCD"*10
In [11]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 307 ns per loop
In [12]: %timeit "XYZ" in s
10000000 loops, best of 3: 81.7 ns per loop
Jak wszyscy wiemy, operacja in
musi przeszukać cały ciąg i startswith
musi tylko sprawdzić kilka pierwszych znaków, więc startswith
powinien być bardziej wydajny .
Kiedy s
jest wystarczająco duża, startswith
jest szybsze:
In [13]: s="ABCD"*200
In [14]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 306 ns per loop
In [15]: %timeit "XYZ" in s
1000000 loops, best of 3: 666 ns per loop
Więc wydaje się, że dzwoni startswith
ma pewne obciążenie co sprawia, że wolniej, gdy ciąg jest niewielka.
A potem próbowałem dowiedzieć się, jaki jest koszt połączenia startswith
.
Najpierw użyłem zmiennej f
do zmniejszenia kosztów eksploatacji kropka - jak wspomniano w tym answer - tutaj widzimy startswith
jest jeszcze wolniej:
In [16]: f=s.startswith
In [17]: %timeit f("XYZ")
1000000 loops, best of 3: 270 ns per loop
Ponadto testowałem kosztu puste wywołanie funkcji:
In [18]: def func(a): pass
In [19]: %timeit func("XYZ")
10000000 loops, best of 3: 106 ns per loop
względu na koszty eksploatacji kropka i działanie połączenia czas startswith
wynosi (270-106) = 164ns, ale tak in
operacji es tylko 81,7ns. Wygląda na to, że nadal istnieją pewne koszty ogólne związane z startswith
, co to jest?
Dodaj wynik testu między startswith
i __contains__
jak sugeruje worku i LVC:
In [28]: %timeit s.startswith("XYZ")
1000000 loops, best of 3: 314 ns per loop
In [29]: %timeit s.__contains__("XYZ")
1000000 loops, best of 3: 192 ns per loop
Aby uzyskać bardziej zbliżony wynik, możesz zrobić 's .__ zawiera __ (" XYZ ")', ponieważ to potrwa tą samą trasę, co 's.startwith (" XYZ ")' następnie (używając operatora 'in' skrót dostępu do członka). Jednak "startswith" jest dla mnie wolniejszy. – poke
Myślę, że pozostała część różnicy w wydajności wynika z tego, że '__contains__' jest w pełni wpisany * w C *, podczas gdy' startswith' robi faktyczne parsowanie argumentów i rzeczy (możesz także przekazać krotkę). – poke
Jakiej wersji Python używasz? W wersji 3.4.3 otrzymuję 's.startswith (" XYZ ")' raport 153ns, a 's .__ zawiera __ (" XYZ ")' raporty 169ns. Jak mówi @poke, użycie 'in' użyje zupełnie innych reguł wyszukiwania niż wywołanie metody - można je wyszukać bezpośrednio ze wskaźnika funkcji na poziomie C, podczas gdy wyszukiwanie metody wykonuje dwa wyszukiwania w słowniku i * wtedy * musi zrobić wywołanie funkcji na poziomie Pythona. Odmienianie tych rzeczy osobno może dać ci * trochę * różnicy, ale niekoniecznie jest dokładne. Na twoich liczbach, odejmowanie obu tych narzutów czyni czas dla 'startswith' * negative *! – lvc