Dziś przeczytałem ten wątek o szybkości konkatenacji ciągów.
O dziwo zwyciężyła konkatenacja ciągów:
Wynik był odwrotny od tego, co myślałem. Poza tym, istnieje wiele artykułów na ten temat, które wyjaśniają przeciwnie jak ten .
Domyślam się, że przeglądarki są zoptymalizowane pod kątem ciągów znaków concat
w najnowszej wersji, ale jak to robią? Czy możemy powiedzieć, że lepiej jest używać +
podczas łączenia ciągów?
Aktualizacja
Tak więc w nowoczesnych przeglądarkach konkatenacja ciągów jest zoptymalizowana, więc używanie +
znaków jest szybsze niż używanie, join
gdy chcesz połączyć ciągi.
Ale @Arthur wskazał, że join
jest to szybsze, jeśli faktycznie chcesz łączyć ciągi za pomocą separatora.
Aktualizacja - 2020
Chrome: tablica join
jest prawie 2 times faster
zgodna ze stringami +
Zobacz: https://stackoverflow.com/a/54970240/984471
Uwaga:
- Tablica
join
jest lepsza, jeśli maszlarge strings
- Jeśli potrzebujemy wygenerować
several small strings
w końcowym wyniku, lepiej jest zastosować konkatację ciągów+
, ponieważ w przeciwnym razie przejście z Array będzie wymagało kilku konwersji Array na String na końcu, co jest przeciążeniem wydajności.
źródło
Odpowiedzi:
Silnik javascript V8 (używany w Google Chrome) używa tego kodu do konkatenacji ciągów:
Tak więc wewnętrznie optymalizują ją, tworząc tablicę InternalArray (
parts
zmienną), która jest następnie wypełniana. Funkcja StringBuilderConcat jest wywoływana z tymi częściami. Jest szybki, ponieważ funkcja StringBuilderConcat to mocno zoptymalizowany kod C ++. Jest za długo, aby cytować w tym miejscu, ale wyszukaj kod w pliku runtime.ccRUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat)
.źródło
arr.join vs str+
na chrome otrzymujesz (w operacjach na sekundę)25k/s vs 52k/s
. w Firefoxie otrzymujesz nowy76k/s vs 212k/s
. więcstr+
jest SZYBSZY. ale spójrzmy na inne przeglądarki. Opera daje 43k / s vs 26k / s. IE podaje1300/s vs 1002/s
. Zobacz co się dzieje? tylko przeglądarka Optymalizacja NEED byłoby lepiej wyłączyć za pomocą tego, co jest wolniejszy na wszystkich innych, w których to nie ma znaczenia w ogóle. Tak więc żaden z tych artykułów nie zawiera informacji na temat wydajności.Firefox jest szybki, ponieważ używa czegoś, co nazywa się Ropes ( Ropes: an Alternative to Strings ). Lina to po prostu DAG, w którym każdy węzeł jest sznurkiem.
Na przykład, gdybyś to zrobił
a = 'abc'.concat('def')
, nowo utworzony obiekt wyglądałby tak. Oczywiście nie tak to wygląda w pamięci, ponieważ nadal musisz mieć pole na typ, długość i być może inne.I
b = a.concat('123')
Tak więc w najprostszym przypadku maszyna wirtualna nie musi wykonywać prawie żadnej pracy. Jedynym problemem jest to, że spowalnia to nieco inne operacje na wynikowym ciągu. Oczywiście zmniejsza to również obciążenie pamięci.
Z drugiej strony
['abc', 'def'].join('')
zwykle przydzielałby pamięć, aby rozłożyć nowy ciąg na płasko w pamięci. (Może to powinno zostać zoptymalizowane)źródło
Wiem, że to stary wątek, ale twój test jest nieprawidłowy. Robisz,
output += myarray[i];
podczas gdy powinno być bardziej,output += "" + myarray[i];
bo zapomniałeś, że musisz coś skleić razem. Kod concat powinien wyglądać mniej więcej tak:W ten sposób wykonujesz dwie operacje zamiast jednej z powodu sklejania elementów ze sobą.
Array.join()
jest szybszy.źródło
"" +
a oryginałem?output
bez niego.Array.join(",")
co nie zadziała z twojąfor
pętląW przypadku dużej ilości danych łączenie jest szybsze, więc pytanie jest sformułowane nieprawidłowo.
Przetestowano na Chrome 72.0.3626.119, Firefox 65.0.1, Edge 42.17134.1.0. Zwróć uwagę, że jest to szybsze nawet przy dołączonym tworzeniu macierzy!
źródło
Tam wzorce są trywialne. Wielokrotne łączenie tych samych trzech elementów zostanie wstawione, wyniki okażą się deterministyczne i zapamiętane, program do obsługi śmieci po prostu wyrzuci obiekty tablicowe (które będą prawie zerowe) i prawdopodobnie po prostu wypchną i wyskoczą ze stosu z powodu braku odniesienia zewnętrzne i ponieważ ciągi znaków nigdy się nie zmieniają. Byłbym pod większym wrażeniem, gdyby test obejmował dużą liczbę losowo generowanych ciągów. Jak na koncercie lub dwóch strunach.
Array.join FTW!
źródło
Powiedziałbym, że w przypadku łańcuchów łatwiej jest wstępnie przydzielić większy bufor. Każdy element ma tylko 2 bajty (jeśli jest UNICODE), więc nawet jeśli jesteś konserwatywny, możesz wstępnie przydzielić całkiem duży bufor dla ciągu. Z
arrays
każdego elementu jest bardziej „złożone”, ponieważ każdy element jestObject
tak konserwatywny realizacja przydzielenia miejsca dla mniejszych elementów.Jeśli spróbujesz dodać
for(j=0;j<1000;j++)
przed każdymfor
, zobaczysz, że (pod chromem) różnica w prędkości zmniejszy się. Ostatecznie było to nadal 1,5x dla konkatenacji ciągów, ale mniejsze niż 2,6, które było wcześniej.ORAZ konieczność skopiowania elementów, znak Unicode jest prawdopodobnie mniejszy niż odniesienie do obiektu JS.
Należy pamiętać, że istnieje możliwość, że wiele implementacji silników JS ma optymalizację dla tablic jednego typu, która sprawiłaby, że wszystko, co napisałem, byłoby bezużyteczne :-)
źródło
Ten test pokazuje karę za faktyczne użycie łańcucha utworzonego za pomocą konkatenacji przypisań w porównaniu z utworzonym metodą array.join. Podczas gdy ogólna prędkość przypisywania jest nadal dwa razy większa w Chrome v31, ale nie jest już tak duża, jak wtedy, gdy nie używasz wynikowego ciągu.
źródło
Zależy to oczywiście od implementacji silnika javascript. Nawet w przypadku różnych wersji jednego silnika można uzyskać znacząco różne wyniki. Powinieneś zrobić własny test porównawczy, aby to zweryfikować.
Powiedziałbym, że
String.concat
ma lepszą wydajność w ostatnich wersjach V8. Ale dla Firefoksa i OperyArray.join
jest zwycięzcą.źródło
Domyślam się, że podczas gdy każda wersja ma koszt wielu konkatenacji, wersje złączeń oprócz tego budują tablice.
źródło