Dlaczego kiedykolwiek Java byłaby szybsza niż C ++?

79

Czasami Java przewyższa C ++ w testach porównawczych. Oczywiście czasami C ++ osiąga lepsze wyniki.

Zobacz następujące linki:

Ale jak to w ogóle możliwe? Dziwi mnie, że interpretacja kodu bajtowego może być szybsza niż skompilowany język.

Czy ktoś może wyjaśnić? Dzięki!

Deets McGeets
źródło
2
Możesz rzucić okiem na shootout.alioth.debian.org/u32/..., aby zobaczyć rodzaje problemów, które działają szybciej na java / c ++ ... Zobacz wzór problemów, a nie te konkretne problemy ...
c0da
2
Zobacz, dlaczego java ma reputację powolności? dla wielu szczegółów na ten temat.
Péter Török
11
Tworzenie maszyny wirtualnej Java, która działa szybciej niż wykonywalny plik binarny utworzony w C ++, jest niezgodne z prawem (Rozdział 10.101.04.2c).
Mateen Ulhaq
1
@muntoo Co do diabła masz na myśli? Sekcja 10.101.04.2c czego?
Highland Mark
3
@HighlandMark Nie jesteś członkiem kręgu. Nie powinieneś wiedzieć, co wchodzi w krąg. Koło jest absolutne - prawa koła zastępują prawa natury. Nie możesz przeciwstawić się ani zakwestionować kręgu. Jestem kołem, a koło to ja.
Mateen Ulhaq

Odpowiedzi:

108

Po pierwsze, większość maszyn JVM zawiera kompilator, więc „interpretowany kod bajtowy” jest w rzeczywistości dość rzadki (przynajmniej w kodzie testowym - nie jest tak rzadki w prawdziwym życiu, w którym Twój kod to zwykle więcej niż kilka trywialnych pętli, które bardzo często się powtarzają ).

Po drugie, spora liczba odnośnych testów porównawczych wydaje się dość tendencyjna (czy to z intencji, czy z niekompetencji, naprawdę nie mogę powiedzieć). Na przykład przed laty patrzyłem na część kodu źródłowego połączonego z jednym z opublikowanych linków. Miał taki kod:

  init0 = (int*)calloc(max_x,sizeof(int));
  init1 = (int*)calloc(max_x,sizeof(int));
  init2 = (int*)calloc(max_x,sizeof(int));
  for (x=0; x<max_x; x++) {
    init2[x] = 0;
    init1[x] = 0;
    init0[x] = 0;
  }

Ponieważ calloczapewnia pamięć, która jest już wyzerowana, forponowne użycie pętli do zera jest oczywiście bezużyteczne. Następnie (jeśli pamięć służy) wypełnianie pamięci i tak innymi danymi (i brak zależności od wyzerowania), więc i tak całe zerowanie było całkowicie niepotrzebne. Zastąpienie powyższego kodu prostą malloc(jak każda rozsądna osoba na początku) poprawiła szybkość wersji C ++ na tyle, aby pokonać wersję Java (o dość szeroki margines, jeśli pamięć służy).

Rozważ (na inny przykład) methcalltest porównawczy użyty we wpisie na blogu w ostatnim linku. Pomimo nazwy (i tego, jak mogłoby to nawet wyglądać), wersja tego C ++ tak naprawdę wcale nie mierzy dużo narzutu wywołania metody. Część kodu, która okazuje się być krytyczna, znajduje się w klasie Toggle:

class Toggle {
public:
    Toggle(bool start_state) : state(start_state) { }
    virtual ~Toggle() {  }
    bool value() {
        return(state);
    }
    virtual Toggle& activate() {
        state = !state;
        return(*this);
    }
    bool state;
};

Kluczową częścią okazuje się state = !state;. Zastanów się, co się stanie, gdy zmienimy kod na kodowanie stanu intzamiast bool:

class Toggle {
    enum names{ bfalse = -1, btrue = 1};
    const static names values[2];
    int state;

public:
    Toggle(bool start_state) : state(values[start_state]) 
    { }
    virtual ~Toggle() {  }
    bool value() {  return state==btrue;    }

    virtual Toggle& activate() {
        state = -state;
        return(*this);
    }
};

Ta niewielka zmiana poprawia ogólną prędkość o około 5: 1 margines . Mimo, że benchmark był przeznaczony do pomiaru czasu metoda połączenia, w rzeczywistości większość tego, co było pomiaru był czas na konwersję pomiędzy inti bool. Z pewnością zgodziłbym się z tym, że nieefektywność wykazana przez oryginał jest niefortunna - ale biorąc pod uwagę, jak rzadko wydaje się występować w prawdziwym kodzie, oraz łatwość, z jaką można to naprawić, kiedy / jeśli się pojawi, trudno jest mi myśleć tego, co wiele znaczy.

W przypadku, gdy ktoś zdecyduje się ponownie uruchomić odnośne testy porównawcze, powinienem również dodać, że istnieje prawie równie trywialna modyfikacja wersji Java, która produkuje (lub przynajmniej raz wyprodukowała - nie uruchomiłem ponownie testów z ostatnie JVM, aby potwierdzić, że nadal tak robią), dość znacząca poprawa również w wersji Java. Wersja Java ma NthToggle :: Activate (), która wygląda następująco:

public Toggle activate() {
this.counter += 1;
if (this.counter >= this.count_max) {
    this.state = !this.state;
    this.counter = 0;
}
return(this);
}

Zmiana tej opcji na wywołanie funkcji podstawowej zamiast this.statebezpośredniego manipulowania daje dość znaczną poprawę prędkości (choć nie wystarcza, aby nadążyć za zmodyfikowaną wersją C ++).

W efekcie powstaje fałszywe założenie dotyczące interpretowanych kodów bajtów w porównaniu do niektórych najgorszych testów porównawczych (jakie kiedykolwiek widziałem). Ani też nie daje znaczącego wyniku.

Moje własne doświadczenie jest takie, że przy równie doświadczonych programistach, którzy zwracają jednakową uwagę na optymalizację, C ++ będzie częściej bić Javę - ale (przynajmniej między tymi dwoma) język rzadko robi tak dużą różnicę, jak programiści i projekt. Cytowane testy porównawcze mówią nam więcej o (nie) kompetencjach / (nie) uczciwości ich autorów niż o językach, które zamierzają przeprowadzać.

[Edycja: Jak sugerowano w jednym miejscu powyżej, ale nigdy nie podano tak bezpośrednio, jak prawdopodobnie powinienem, cytuję wyniki, które otrzymałem, kiedy testowałem to ~ 5 lat temu, używając implementacji C ++ i Java, które były aktualne w tym czasie . Nie uruchomiłem ponownie testów z bieżącymi implementacjami. Rzut oka wskazuje jednak, że kod nie został naprawiony, więc wszystko, co by się zmieniło, to zdolność kompilatora do ukrywania problemów w kodzie.]

Jeśli jednak zignorujemy przykłady Java, w rzeczywistości jest możliwe, że interpretowany kod działa szybciej niż kod skompilowany (choć trudny i nieco nietypowy).

Zwykle dzieje się tak, gdy interpretowany kod jest znacznie bardziej zwarty niż kod maszynowy lub działa na procesorze, który ma większą pamięć podręczną danych niż pamięć podręczna kodu.

W takim przypadku mały interpreter (np. Wewnętrzny interpreter implementacji Fortha) może całkowicie zmieścić się w pamięci podręcznej kodu, a program, który interpretuje, mieści się całkowicie w pamięci podręcznej danych. Pamięć podręczna jest zwykle szybsza niż pamięć główna dziesięciokrotnie, a często znacznie więcej (współczynnik 100 nie jest już szczególnie rzadki).

Jeśli więc pamięć podręczna jest szybsza niż pamięć główna o współczynnik N, a do wdrożenia każdego kodu bajtu potrzeba mniej niż N instrukcji kodu maszynowego, kod bajtów powinien wygrać (upraszczam, ale myślę, że ogólna idea powinna nadal być widocznym).

Jerry Coffin
źródło
26
+1, pełne potwierdzenie. Zwłaszcza „język rzadko robi tak wielką różnicę, jak programiści i projekt” - często natkniesz się na problemy, w których możesz zoptymalizować algorytm, np. Poprawić big-O, co da znacznie więcej doładowania niż najlepszy kompilator.
schnaader
1
„W przypadku, gdy ktoś zdecyduje się ponownie uruchomić odnośne testy ...” NIE! W 2005 r. Te stare zadania zostały odrzucone i zastąpione zadaniami wyświetlanymi teraz w grze porównawczej. Jeśli ktoś chce ponownie uruchomić niektóre programy, uruchom ponownie bieżące programy dla bieżących zadań pokazanych na stronie głównej gry porównawczej shootout.alioth.debian.org
igouy
@igouy: Niektóre osoby mogą chcieć po prostu potwierdzić / zaprzeczyć wynikom testów, które przeprowadzili, przy minimalnej liczbie niezbędnych korekt, aby przynajmniej dać im minimalny związek z rzeczywistością. Jednocześnie masz rację: omawiane testy porównawcze są tak złe, że naprawienie najbardziej oczywistych błędów niewiele pomoże.
Jerry Coffin,
I dlatego w 2005 r. Zostały odrzucone i zastąpione zadaniami pokazanymi w grze testowej. Ludzie, którzy nie wiedzą nic lepszego, ponownie uruchamiają te stare programy.
igouy
13
+1 Nie lubię ludzi, którzy kodują C ++ w stylu C lub Java, a następnie twierdzą, że Java jest lepsza. zrzeczenie się: Nie nazywam żadnego języka lepszym, ale pisanie kiepskiego kodu C ++ w stylu, który może być idealnie dopasowany do innego języka, nie czyni obu języków porównywalnymi.
Christian Rau,
111

Ręcznie walcowane C / C ++ wykonane przez eksperta z nieograniczonym czasem będzie co najmniej tak szybkie lub szybsze niż Java. Ostatecznie sama Java jest napisana w C / C ++, więc możesz oczywiście zrobić wszystko, co robi Java, jeśli chcesz włożyć wystarczająco dużo wysiłku inżynieryjnego.

W praktyce jednak Java często wykonuje się bardzo szybko z następujących powodów:

  • Kompilacja JIT - chociaż klasy Java są przechowywane jako kod bajtowy, jest to (zwykle) kompilowane do kodu natywnego przez kompilator JIT podczas uruchamiania programu. Po skompilowaniu jest to czysty kod macierzysty - teoretycznie można oczekiwać, że będzie działał równie dobrze jak skompilowany C / C ++, gdy program będzie działał wystarczająco długo (tj. Po zakończeniu kompilacji JIT)
  • Odśmiecanie w Javie jest niezwykle szybkie i wydajne - Hotspot GC jest prawdopodobnie najlepszą wszechstronną implementacją GC na świecie. Jest to wynik wielu lat wysiłków ekspertów firmy Sun i innych firm. Gorzej będzie z każdym złożonym systemem zarządzania pamięcią, który rzucisz w C / C ++. Oczywiście możesz pisać dość szybkie / lekkie podstawowe schematy zarządzania pamięcią w C / C ++, ale nie będą one tak wszechstronne jak pełny system GC. Ponieważ większość współczesnych systemów wymaga złożonego zarządzania pamięcią, Java ma zatem dużą zaletę w rzeczywistych sytuacjach.
  • Lepsze celowanie na platformę - kompilator Java może opóźnić kompilację do uruchomienia aplikacji (kompilacja JIT itp.), Ponieważ zna dokładny procesor, na którym działa. Może to umożliwić bardzo korzystne optymalizacje, których nie byłbyś w stanie zrobić we wstępnie skompilowanym kodzie C / C ++, który musi być ukierunkowany na zestaw instrukcji procesora „najniższy wspólny mianownik”.
  • Statystyki środowiska wykonawczego - ponieważ kompilacja JIT odbywa się w czasie wykonywania, może gromadzić statystyki podczas wykonywania programu, które umożliwiają lepszą optymalizację (np. Wiedząc o prawdopodobieństwie przyjęcia określonej gałęzi). Może to umożliwić kompilatorom Java JIT tworzenie lepszego kodu niż kompilatory C / C ++ (które muszą wcześniej „odgadnąć” najbardziej prawdopodobną gałąź, co może być często błędne).
  • Bardzo dobre biblioteki - środowisko wykonawcze Java zawiera wiele bardzo dobrze napisanych bibliotek o dobrej wydajności (szczególnie dla aplikacji po stronie serwera). Często są one lepsze niż te, które można napisać samodzielnie lub łatwo uzyskać w C / C ++.

Jednocześnie C / C ++ mają również pewne zalety:

  • Więcej czasu na zaawansowane optymalizacje - kompilacja C / C ++ jest wykonywana raz, a zatem może poświęcić dużo czasu na zaawansowane optymalizacje, jeśli ją skonfigurujesz. Nie ma teoretycznego powodu, dla którego Java nie mogłaby zrobić tego samego, ale w praktyce chcesz, aby Java kompilowała kod JIT stosunkowo szybko, więc kompilator JIT zwykle koncentruje się na „prostszych” optymalizacjach.
  • Instrukcje, których nie można wyrazić w kodzie bajtowym - podczas gdy kod bajtowy Java jest w pełni ogólny, nadal istnieje kilka rzeczy, które możesz zrobić na niskim poziomie, których nie możesz zrobić w kodzie bajtowym (dobrym przykładem jest niezaznaczona arytmetyka wskaźnika!). Używając (ab) tych sztuczek, możesz uzyskać pewne korzyści w zakresie wydajności
  • Mniejsze ograniczenia „bezpieczeństwa” - Java wykonuje dodatkowe prace, aby zapewnić bezpieczeństwo i niezawodność programów. Przykładami są kontrole granic tablic, pewne gwarancje współbieżności, kontrole zerowych wskaźników, bezpieczeństwo typów rzutowań itp. Unikając ich w C / C ++, można uzyskać pewien wzrost wydajności (choć prawdopodobnie to zły pomysł!)

Ogólny:

  • Java i C / C ++ mogą osiągnąć podobne prędkości
  • C / C ++ prawdopodobnie ma niewielką przewagę w ekstremalnych okolicznościach (nic dziwnego, że twórcy gier AAA nadal wolą, na przykład)
  • W praktyce będzie to zależeć od tego, jak różne czynniki wymienione powyżej równoważą się dla konkretnego zastosowania.
mikera
źródło
9
Reklama „więcej czasu na optymalizacje w C ++”: To jedna z drobnych poprawek, które robi Oracle VM, kiedy wybierasz VM maszyny: Akceptuje wyższe koszty początkowe, aby umożliwić wyższą wydajność w dłuższej perspektywie. Maszyna wirtualna klienta jest jednak dostosowywana pod kątem optymalnego czasu uruchamiania. To rozróżnienie istnieje nawet w Javie.
Joachim Sauer
8
-1: Kompilator C ++ może zająć znacznie więcej czasu (dosłownie, dla dużej biblioteki) godzin, aby utworzyć bardzo zoptymalizowany plik binarny. Kompilator Java JIT nie może zająć tak dużo czasu, nawet wersja „serwerowa”. Poważnie wątpię, czy kompilator Java JIT byłby w stanie przeprowadzić Optymalizację całego programu, tak jak kompilator MS C ++.
quant_dev,
20
@quant_dev: jasne, ale czy nie jest to dokładnie to, co powiedziałem w mojej odpowiedzi jako przewaga w C ++ (więcej czasu na zaawansowaną optymalizację)? Dlaczego więc -1?
mikera
13
Wyrzucanie elementów bezużytecznych nie jest zaletą szybkości dla Java. Jest to tylko przewaga prędkości, jeśli jesteś programistą C ++, który nie wie, co robisz. Jeśli wszystko, co sprawdzasz, to jak szybko możesz przydzielić, to tak, śmieciarz wygra. Jednak ogólną wydajność programu można nadal lepiej wykonać ręcznie zarządzając pamięcią.
Billy ONeal,
4
... Ale w C ++ zawsze możesz teoretycznie umieścić „warstwę podobną do JIT”, która wykonuje podobne optymalizacje gałęzi w czasie wykonywania, przy jednoczesnym zachowaniu surowej prędkości programu C ++. (Teoretycznie. :()
Mateen Ulhaq
19

Środowisko wykonawcze Java nie interpretuje kodu bajtowego. Zamiast tego wykorzystuje tak zwaną kompilację Just In Time . Zasadniczo, gdy program jest uruchomiony, pobiera kod bajtowy i konwertuje go na kod natywny zoptymalizowany dla konkretnego procesora.

Grandmaster B.
źródło
W praktyce tak. Zasadniczo to zależy - wczesne maszyny wirtualne Java korzystały z interpreterów kodu bajtowego i prawdopodobnie nadal można znaleźć maszyny wirtualne z interpretacją kodu bajtowego, jeśli spojrzysz wystarczająco mocno.
Steve314,
10
@ Steve314: ale maszyny wirtualne interpretujące nie będą tymi, które przewyższają C ++, więc nie są tak naprawdę związane z tym pytaniem.
Joachim Sauer
Kompilator JIT może również optymalizować dynamicznie pod kątem konkretnego użycia kodu, co nie jest możliwe w przypadku kodu kompilowanego statycznie.
starblue
2
@starblue, cóż, jest to możliwe dzięki kompilacji statycznej - zobacz optymalizację pod kątem profilu.
SK-logic,
18

Wszystkie rzeczy są równe, można powiedzieć: nie, Java nigdy nie powinna być szybsza . Zawsze możesz zaimplementować Javę w C ++ od podstaw, a tym samym uzyskać co najmniej tak dobrą wydajność. W praktyce jednak:

  • JIT kompiluje kod na komputerze użytkownika końcowego, umożliwiając optymalizację pod kątem dokładnie uruchomionego procesora. Kompilacja wiąże się z dodatkowymi kosztami, ale może się opłacać w przypadku intensywnych aplikacji. Często rzeczywiste programy nie są kompilowane dla używanego procesora.
  • Kompilator Java może być lepszy w automatycznej optymalizacji niż kompilator C ++. A może nie, ale w prawdziwym świecie rzeczy nie zawsze są idealne.
  • Wydajność może się różnić z powodu innych czynników, takich jak wyrzucanie elementów bezużytecznych. W C ++ zwykle wywołujesz destruktor natychmiast po zakończeniu pracy z obiektem. W Javie po prostu uwalniasz odniesienie, opóźniając faktyczne zniszczenie. To kolejny przykład różnicy wydajności, której nie ma ani tu, ani tam. Oczywiście można argumentować, że można zaimplementować GC w C ++ i zrobić to, ale w rzeczywistości niewiele osób robi / chce / może.

Nawiasem mówiąc, przypomina mi to debatę dotyczącą C w latach 80. / 90. Wszyscy zastanawiali się „czy C może być tak szybki jak zgromadzenie?”. Zasadniczo odpowiedź brzmiała: nie na papierze, ale w rzeczywistości kompilator C stworzył wydajniejszy kod niż 90% programistów asemblerowych (cóż, kiedy już trochę dojrzał).

Daniel B.
źródło
2
Jeśli chodzi o GC, nie chodzi tylko o to, że GC może opóźnić niszczenie przedmiotów (co nie powinno mieć znaczenia w dłuższej perspektywie); faktem jest, że we współczesnych GC przydzielanie / zwalnianie obiektów krótkotrwałych jest wyjątkowo tanie w Javie w porównaniu do C ++.
Péter Török
@ PéterTörök tak, masz rację, dobry punkt.
Daniel B
9
@ PéterTörök Ale w C ++ obiekty krótkotrwałe są często umieszczane na stosie, co z kolei jest znacznie szybsze niż jakakolwiek sterta GC edytowana przez Javę.
quant_dev,
@ quant_dev, zapomniałeś o innym znaczącym efekcie GC: kompaktowaniu. Nie byłbym więc pewien, która droga jest szybsza.
SK-logic
3
@DonalFellows Co sprawia, że ​​myślisz, że muszę się martwić o zarządzanie pamięcią w C ++? Przez większość czasu nie. Musisz zastosować proste wzorce, które różnią się od Javy, ale to wszystko.
quant_dev
10

Ale alokacja to tylko połowa zarządzania pamięcią - dealokacja to druga połowa. Okazuje się, że dla większości obiektów bezpośredni koszt wywozu śmieci wynosi - zero. Wynika to z faktu, że moduł kopiujący nie musi odwiedzać ani kopiować martwych obiektów, tylko żywe. Tak więc obiekty, które stają się śmieciami wkrótce po alokacji, nie obciążają cyklu roboczego.

...

Maszyny JVM są zaskakująco dobre w ustalaniu rzeczy, które zakładaliśmy, że tylko programista może wiedzieć. Pozwalając JVM na wybór między alokacją stosu a alokacją sterty w poszczególnych przypadkach, możemy uzyskać korzyści wydajnościowe alokacji stosu bez zmuszenia programisty do zastanowienia się, czy alokować na stosie, czy na stercie.

http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html

Landei
źródło
Jest to tylko niewielka część całego obrazu, ale mimo to bardzo istotne.
Joachim Sauer
2
Podoba mi się, jaka jest tego sedno: java jest dla noobów, zaufaj magii GC, wie lepiej.
Morg.
1
@Morg: Lub możesz to przeczytać w ten sposób: Java jest dla ludzi, którzy lubią robić rzeczy zamiast marnować czas na kręcenie się i ręczne zarządzanie pamięcią.
Landei
4
@Landei Myślę, że twój komentarz byłby znacznie bardziej wiarygodny, gdyby napisano jakąkolwiek przyzwoitą, długotrwałą i powszechnie używaną bazę kodu w Javie. W moim świecie prawdziwe systemy operacyjne są napisane w C, postgreSQL jest napisany w C, podobnie jak najważniejsze narzędzia, których przepisywanie byłoby naprawdę trudne. Java była (i to nawet oficjalna wersja), aby umożliwić mniej wykwalifikowanym ludziom programowanie w stadach, a jednocześnie osiąganie wymiernych rezultatów.
Morg.
1
@Morg Wydaje mi się, że to dziwne, jak skupiasz się tylko na systemach operacyjnych. To po prostu nie może być dobrym rozwiązaniem z kilku powodów. Po pierwsze, wymagania systemów operacyjnych są zasadniczo odmienne od większości innych programów, po drugie masz zasadę Panda thumb (kto chce przepisać kompletny system operacyjny w innym języku, kto chce napisać własny system operacyjny, jeśli istnieją działające, a nawet bezpłatne alternatywy?) a po trzecie inne oprogramowanie korzysta z funkcji systemu operacyjnego, więc nie trzeba pisać sterownika dysku, menedżera zadań itp. Jeśli nie możesz podać lepszych argumentów (nie opartych wyłącznie na systemach operacyjnych), brzmisz jak hejter.
Landei,
5

Podczas gdy całkowicie zoptymalizowany program Java rzadko pokonuje całkowicie zoptymalizowany program C ++, różnice w takich rzeczach jak zarządzanie pamięcią mogą sprawić, że wiele algorytmów jest idiomatycznie zaimplementowanych w Javie szybciej niż te same algorytmy idiomatycznie zaimplementowane w C ++.

Jak zauważył @Jerry Coffin, istnieje wiele przypadków, w których proste zmiany mogą znacznie przyspieszyć kod - ale często może to wymagać zbyt wiele nieczystych poprawek w jednym lub drugim języku, aby poprawa wydajności była opłacalna. To prawdopodobnie zobaczysz w dobrym teście porównawczym, który pokazuje, że Java radzi sobie lepiej niż C ++.

Ponadto, choć zwykle nie jest to aż tak znaczące, istnieje pewna optymalizacja wydajności, której język JIT, taki jak Java, może zrobić, czego nie potrafi C ++. Środowisko wykonawcze Java może zawierać ulepszenia po skompilowaniu kodu, co oznacza, że ​​JIT może potencjalnie wygenerować zoptymalizowany kod, aby skorzystać z nowych (lub przynajmniej różnych) funkcji procesora. Z tego powodu 10-letni plik binarny Java może potencjalnie przewyższyć 10-letni plik binarny C ++.

Wreszcie, pełne bezpieczeństwo typu na szerszym obrazie może, w bardzo rzadkich przypadkach, zaoferować ekstremalną poprawę wydajności. Singularity , eksperymentalny system operacyjny napisany prawie całkowicie w języku C #, ma znacznie szybszą komunikację międzyprocesową i wielozadaniowość ze względu na fakt, że nie ma potrzeby granicznych procesów sprzętowych ani kosztownych przełączników kontekstowych.

Rei Miyasaka
źródło
5

Wysłane przez Tim Holloway na JavaRanch:

Oto prymitywny przykład: Kiedy maszyny działały w określonych matematycznie cyklach, instrukcja rozgałęzienia zwykle miała 2 różne czasy. Jeden, gdy gałąź została przejęta, jeden, gdy gałąź nie została przejęta. Zwykle sprawa bez odgałęzienia była szybsza. Oczywiście oznaczało to, że można zoptymalizować logikę na podstawie wiedzy o tym, który przypadek był bardziej powszechny (z zastrzeżeniem, że to, co „wiemy”, nie zawsze tak naprawdę jest).

Ponowna kompilacja JIT idzie o krok dalej. Monitoruje rzeczywiste wykorzystanie w czasie rzeczywistym i odwraca logikę w oparciu o to, co w rzeczywistości jest najczęstszym przypadkiem. I odwróć to ponownie, jeśli obciążenie się zmieni. Statycznie skompilowany kod nie może tego zrobić. W ten sposób Java może czasami przewyższyć ręcznie dostosowany kod asemblera / C / C ++.

Źródło: http://www.coderanch.com/t/547458/Performance/java/Ahead-Time-vs-Just-time

Thiago Negri
źródło
3
I znowu jest to źle / niekompletnie. Kompilatory statyczne z optyką sterowaną profilem mogą to rozpoznać.
Konrad Rudolph,
2
Konrad, statyczne kompilatory mogą zmienić logikę w oparciu o bieżące obciążenie pracą? Jak rozumiem, kompilatory statyczne generują kod raz i pozostają takie same na zawsze.
Thiago Negri,
2
Bieżące obciążenie pracą, nr Ale typowe obciążenie pracą. Optymalizacja sterowana profilem analizuje działanie programu przy typowym obciążeniu i odpowiednio optymalizuje punkty aktywne, podobnie jak HotSpot JIT.
Konrad Rudolph
4

Wynika to z faktu, że ostatni etap generowania kodu maszynowego odbywa się transparentnie wewnątrz JVM podczas uruchamiania programu Java, zamiast jawnego podczas budowania proramu C ++.

Należy wziąć pod uwagę fakt, że współczesne maszyny JVM spędzają sporo czasu na kompilowaniu kodu bajtowego w locie do natywnego kodu maszynowego, aby uczynić go tak szybko, jak to możliwe. Dzięki temu JVM może wykonywać wszelkiego rodzaju sztuczki kompilatora, które mogą być jeszcze lepsze, znając dane profilowania uruchomionego programu.

Właśnie taka rzecz, jak automatyczne wstawianie gettera, aby JUMP-RETURN nie był potrzebny do uzyskania wartości, przyspiesza rzeczy.

Jednak rzeczą, która naprawdę pozwoliła na szybkie programy, jest lepsze późniejsze czyszczenie. Mechanizm wyrzucania elementów bezużytecznych w Javie jest szybszy niż ręczny bez malloc w C. Wiele współczesnych implementacji wolnych od malloc korzysta ze śmieci pod spodem.


źródło
Zauważ, że te osadzone rzeczy sprawiają, że uruchamianie JVM jest większe i wolniejsze, dopóki lepszy kod nie będzie w stanie go dogonić.
1
„Wiele nowoczesnych implementacji wolnych od malloc wykorzystuje pod śmietnikiem”. Naprawdę? Chciałbym wiedzieć więcej; Czy masz jakieś referencje?
Sean McMillan,
Dziękuję Ci. Próbowałem znaleźć sposób, aby powiedzieć, że JVM nie zawiera już po prostu kompilatora „just in time” kompilującego się do kodu wykonywalnego, ale kompilator „hot spot”, który profiluje działający kod i w rezultacie dalej optymalizuje. I jednorazowy kompilator, taki jak C ++, próbuje to dopasować.
Highland Mark
@SeanMcMillan, kiedyś widziałem analizę dotyczącą wydajności implementacji wolnych od malloc, w której wspomniano, że najszybsza z nich używa podśmiecacza śmieci. Nie pamiętam, gdzie to czytam.
Czy to był konserwatywny GC BDW?
Demi
4

Krótka odpowiedź - nie jest. Zapomnij, temat jest tak stary jak ogień lub koło. Java lub .NET nie jest i nie będzie szybszy niż C / C ++. Jest wystarczająco szybki do większości zadań, w których nie trzeba w ogóle myśleć o optymalizacji. Podobnie jak formularze i przetwarzanie SQL, ale na tym się kończy.

W przypadku testów porównawczych lub małych aplikacji napisanych przez niekompetentnych programistów tak, końcowy rezultat będzie taki, że Java / .NET prawdopodobnie będzie blisko, a może nawet szybciej.

W rzeczywistości proste rzeczy, takie jak przydzielanie pamięci na stosie lub po prostu używanie stref pamięci, po prostu zabijają Java / .NET na miejscu.

Śmieciowy świat używa rodzaju memów z całą księgowością. Dodaj strefę C do C, a C będzie tam szybciej. Zwłaszcza dla testów porównawczych „wysokowydajnego kodu” Java vs. C, które wyglądają następująco:

for(...)
{
alloc_memory//Allocating heap in a loop is verrry good, in't it?
zero_memory//Extra zeroing, we really need it in our performance code
do_stuff//something like memory[i]++
realloc//This is lovely speedup
strlen//loop through all memory, because storing string length is soo getting old
free//Java will do that outside out timing loop, but oh well, we're comparing apples to oranges here
}//loop 100000 times

Spróbuj użyć zmiennych opartych na stosie w C / C ++ (lub umieszczenie nowego), tłumaczą się na sub esp, 0xffto, jest to pojedyncza instrukcja x86, pobij to w Javie - nie możesz ...

Przez większość czasu widzę te ławy, w których porównuje się Javę z C ++, co powoduje, że zaczynam, wth? Niewłaściwe strategie alokacji pamięci, samorosnące pojemniki bez rezerw, wiele nowości. Nie jest to nawet bliskie zorientowanemu na wydajność kodowi C / C ++.

Również dobra lektura: https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf

Koder
źródło
1
Źle. Zupełnie źle. Dzięki ręcznemu zarządzaniu pamięcią nie będziesz w stanie przewyższyć kompaktującego GC. Naiwne liczenie referencji nigdy nie będzie lepsze niż właściwy znak mark'n's weep. Gdy tylko dojdzie do skomplikowanego zarządzania pamięcią, C ++ jest opóźniony.
SK-logic
3
@ SK-Logic: Źle, w przypadku stref pamięci lub alokacji stosów NIE ma alokacji pamięci ani jej dezalokacji. Masz blok pamięci i po prostu do niego piszesz. Oznacz blok jako wolny za pomocą zmiennych zmiennych, takich jak ochrona współbieżności InterlockedExchange itp., A następny wątek po prostu zrzuca swoje dane do wstępnie przydzielonego bloku, nie przechodząc do systemu operacyjnego po pamięć, jeśli widzi, że jest wolny. W stosie jest to jeszcze łatwiejsze, z tym wyjątkiem, że nie można zrzucić 50 MB na stosie. Żywotność tego obiektu jest tylko w środku {}.
Koder
2
@ SK-logic: Kompilatory są najpierw poprawnością, a wydajnością drugą. Wyszukiwarki, silniki baz danych, systemy handlu w czasie rzeczywistym, gry uważam za kluczowe dla wydajności. I większość z nich opiera się na płaskich strukturach. Tak czy inaczej, kompilatory są w większości napisane w C / C ++. Chyba z niestandardowymi alokatorami. Z drugiej strony nie widzę problemów z użyciem elementów drzewa lub listy nad rammap. Po prostu używasz nowego miejsca docelowego. Nie ma w tym żadnej złożoności.
Koder
3
@ SK-logic: Nie jest to dużo szybsze, każda aplikacja .NET / Java, którą widziałem, zawsze okazała się wolniejsza i prawdziwa świnia. Każde przepisanie zarządzanej aplikacji do kodu SANE C / C ++ skutkowało czystszą i lżejszą aplikacją. Zarządzane aplikacje są zawsze ciężkie. Zobacz VS2010 vs 2008. Te same struktury danych, ale VS2010 jest HOG. Prawidłowo napisane aplikacje C / C ++ zwykle uruchamiają się w milisekundach i nie blokują się na ekranach powitalnych, zużywając jednocześnie znacznie mniej pamięci. Jedynym minusem jest to, że musisz kodować z myślą o sprzęcie, a wiele osób nie wie, jak to jest obecnie. To tylko punkty odniesienia, w których zarządzani mają szansę.
Koder
2
twoje anegdotyczne dowody się nie liczą. Właściwe testy porównawcze pokazują prawdziwą różnicę. Szczególnie dziwne jest to, że masz na myśli aplikacje GUI powiązane z obszernymi i nieoptymalnymi bibliotekami GUI. Co ważniejsze - teoretycznie limit wydajności jest znacznie wyższy dla prawidłowo wdrożonego GC.
SK-logic
2

W rzeczywistości są to tylko asemblery wysokiego poziomu, które robią dokładnie to, co prosi programista, dokładnie tak, jak prosi programista w dokładnie takiej kolejności, w jakiej prosi programista. Różnice w wydajności są tak małe, że są nieistotne dla wszystkich praktycznych celów.

Język nie jest „wolny”, programista napisał wolny program. Bardzo rzadko program napisany w najlepszy sposób w jednym języku poza (w jakimkolwiek praktycznym celu) program robi to samo przy użyciu najlepszego sposobu w języku alternatywnym, chyba że autor badania zamierza zmielić swój topór.

Oczywiście, jeśli wybierasz się na rzadki przypadek, taki jak twarde systemy osadzone w czasie rzeczywistym, wybór języka może mieć znaczenie, ale jak często tak jest? a w tych przypadkach, jak często właściwy wybór nie jest ślepo oczywisty.

mattnz
źródło
2
Teoretycznie „idealna” maszyna wirtualna JITting musi osiągać lepsze wyniki niż skompilowany statycznie kod, dostosowując swoje optymalizacje do dynamicznie gromadzonych informacji profilowania. W praktyce kompilatory JIT nie są jeszcze tak inteligentne, ale przynajmniej są w stanie wygenerować kod o podobnej jakości, jak w przypadku ich większych i wolniejszych statycznych elementów równorzędnych.
SK-logic,
2

Zobacz poniższe linki ... Ale jak to w ogóle możliwe? Dziwi mnie, że interpretacja kodu bajtowego może być szybsza niż skompilowany język.

  1. Czy te posty na blogu dostarczają wiarygodnych dowodów?
  2. Czy te posty na blogu dostarczają ostatecznych dowodów?
  3. Czy te posty na blogu zawierają nawet dowody na temat „interpretowanego kodu bajtowego”?

Keith Lea mówi ci, że są „oczywiste wady”, ale nie robi nic z tymi „oczywistymi wadami”. W 2005 r. Te stare zadania zostały odrzucone i zastąpione zadaniami wyświetlanymi teraz w grze porównawczej .

Keith Lea mówi ci, że „wziął kod porównawczy dla C ++ i Java z przestarzałej Great Computer Language Shootout i przeprowadził testy”, ale w rzeczywistości pokazuje tylko pomiary dla 14 z 25 tych nieaktualnych testów .

Keith Lea mówi teraz, że nie próbował niczego udowodnić postem na blogu siedem lat wcześniej, ale wtedy powiedział: „Miałem dość słuchania, jak ludzie mówią, że Java jest wolna, kiedy wiem, że jest dość szybka ...”, co sugeruje wtedy było coś, co próbował udowodnić.

Christian Felde mówi ci: „Nie stworzyłem kodu, po prostu ponownie uruchomiłem testy”. jakby to zwolniło go z wszelkiej odpowiedzialności za decyzję o opublikowaniu pomiarów zadań i programów wybranych przez Keitha Leę.

Czy pomiary nawet 25 maleńkich programów dostarczają ostatecznych dowodów?

Pomiary te są dla programów uruchamianych jako „tryb mieszany” Java nie interpretuje Java - „Pamiętam, jak działa HotSpot” Możesz łatwo dowiedzieć się, jak dobrze Java uruchamia „interpretowany kod bajtowy”, ponieważ możesz zmusić Javę do interpretowania tylko kodu bajtowego - wystarczy, że niektóre programy Java uruchomią się z opcją -Xint i bez niej.

igouy
źródło
-1

Bawi mnie, jak wszechobecne jest to dziwne pojęcie „interpretowanego kodu bajtowego”. Czy słyszeliście kiedyś o kompilacji JIT? Twojego argumentu nie można zastosować do Javy.

Ale pomijając JVM, zdarzają się przypadki, gdy bezpośredni kod wątkowy lub nawet trywialna interpretacja kodu bajtowego może łatwo przewyższyć mocno zoptymalizowany kod macierzysty. Wyjaśnienie jest dość proste: kod bajtowy może być dość kompaktowy i zmieści się w twojej małej pamięci podręcznej, gdy natywna wersja kodu tego samego algorytmu skończy się z kilkoma brakami pamięci podręcznej dla jednej iteracji.

Logika SK
źródło
Wszechobecność interpretacji jest prawdopodobnie spowodowana ludźmi znającymi się na informatyce. Maszyna wirtualna Java jest maszyną, która akceptuje kod bajtowy Java i uruchamia go na komputerze / nie / zdolnym do natywnego uruchamiania kodu bajtowego Java, bez możliwości napisania funkcjonalnie równoważnego programu macierzystego. Ergo to tłumacz. Możesz nadać jego technikom buforowania dowolną nazwę, którą możesz wymyślić, JIT lub inną, ale jest to tłumacz z definicji tłumacza.
thiton
@thiton, są szanse, że twój własny CS-fu jest trochę słaby. JVM nie zrobić każdy rodzaj interpretacji (dla hot spotów) - jako ktoś, kto odważy się wspomnieć CS, ty masz wiedzieć, co to znaczy, i jak an semantyka operacyjna interpretacji różni się od prowadzenia natywnego kodu. Ale prawdopodobnie po prostu nie znasz wystarczająco dużo CS, aby odróżnić kompilację od interpretacji.
SK-logic,
2
Umm, ale kod bajtowy, aby go uruchomić, musi zostać przekonwertowany na kod macierzysty - nie można podać kodu bajtowego Java do procesora. Zatem argument wielkości jest nieprawidłowy.
quant_dev,
@ quant_dev, oczywiście - powiedziałem, że ta sprawa jest całkowicie niezwiązana z JVM. Aby ten efekt działał, potrzebujesz znacznie prostszego silnika kodu bajtowego.
SK-logic
-1

Poza JIT, GC i tak dalej, C ++ może być bardzo, bardzo łatwo spowolniony o wiele bardziej niż Java. Nie pojawi się to w testach porównawczych, ale ta sama aplikacja napisana przez programistę Java i programistę C ++ może być znacznie szybsza w Javie.

  • Przeciążenie operatora. Każdy prosty operator, taki jak „+” lub „=”, może wywoływać setki linii kodu wykonujących kontrole bezpieczeństwa, operacje na dyskach, logowanie, śledzenie i profilowanie. Są tak łatwe w użyciu, że gdy przeciążasz operatorów, używasz ich naturalnie i obficie, nie zauważając, w jaki sposób nakładają się one na siebie.
  • Szablony Nie wpływają one na szybkość tak samo jak pamięć. Nieostrożne użycie szablonów doprowadzi do wygenerowania milionów wierszy kodu (alternatywy dla podstawowego szablonu) bez ich zauważania. Ale potem czasy ładowania binarnego, użycie pamięci, użycie wymiany - wszystko to działa również wbrew testom porównawczym. A użycie pamięci RAM przechodzi przez dach.

Jeśli chodzi o zaawansowane wzorce dziedziczenia, są one prawie do siebie podobne - C ++ ma takie, których Java nie ma i odwrotnie, ale wszystkie wprowadzają podobny, znaczny narzut. Więc nie ma żadnej specjalnej korzyści C ++ w programowaniu z dużym obciążeniem obiektowym.

Jeszcze jedno zastrzeżenie: GC może być szybsze lub wolniejsze niż ręczne zarządzanie przydziałami. Jeśli przydzielisz wiele małych obiektów, w środowisku GC zwykle przydzielana jest część pamięci i wysyłane są jej fragmenty w razie potrzeby dla nowych obiektów. W zarządzaniu - każdy obiekt = oddzielny przydział zajmuje dużo czasu. OTOH, jeśli malloc () dużo pamięci naraz, a następnie po prostu ręcznie przypisujesz jej część do swoich obiektów lub używasz kilku większych instancji obiektów, możesz znaleźć je znacznie szybciej.

SF.
źródło
4
Nie zgadzam się z obydwoma punktami. To, czy korzystasz z operatorów, czy metod, nie ma znaczenia. Mówisz, że będą się rozmnażać. Bzdury - nie więcej niż metody; albo musisz do nich zadzwonić, albo nie. A szablony dają nie więcej kodu niż ręczne pisanie tego konkretnego kodu do wielokrotnego użytku. Może być więcej kodu niż przy uruchamianiu środowiska uruchomieniowego (funkcje wirtualne), ale to również nie będzie miało znaczenia: wydajność linii pamięci podręcznej instrukcji ma największe znaczenie w ciasnych pętlach, a tutaj będzie używana tylko jedna instancja szablonu, więc nie ma odpowiedniego nacisku pamięci ze względu na szablony.
Konrad Rudolph,
Zazwyczaj uważa się, że metody są drogie, a operatorzy tanie. Korzystasz z metod, gdy musisz, operatorzy, gdy chcesz zaoszczędzić czas i zoptymalizować. To nie jest kwestia techniczna, ale psychologiczna - nie chodzi o to, że operatorzy są „ciężsi”, są po prostu o wiele łatwiejsi w użyciu i są częściej używani. (plus można przeciążać powszechnie używanego operatora wcześniej istniejącym kodem, co czyni go tym samym co oryginalny, plus dodatkowy - i nagle cały kod znacznie zwolni.
SF.
Kwestionuję, że ten fakt psychologiczny jest prawdziwy, a nawet jeśli tak, to nie masz wyboru : jeśli potrzebujesz funkcjonalności, korzystasz z niej, niezależnie od tego, czy jest zawarta w operatorze, czy w metodzie. Psychologia nie ma znaczenia dla wyboru semantyki.
Konrad Rudolph,
1
Podchwytliwe pytanie. W ogóle nie zgadywałbym tego, zmierzałbym, działał wtedy . Nigdy nie miałem problemu z tą taktyką.
Konrad Rudolph
1
@KonradRudolph: To wszystko jest prawdą, jeśli chodzi o przejrzystość i łatwość pisania kodu, dzięki czemu jest wolny od błędów i łatwy w utrzymaniu. Jednak kwestia wydajności implementacji algorytmu nadal jest ważna: jeśli masz zamiar napisać obj.fetchFromDatabase("key")trzy razy w ciągu pięciu wierszy kodu dla tego samego klucza, dwa razy zastanów się, czy pobrać tę wartość raz i zapisać ją w pamięci lokalnej. Jeśli piszesz obj->"key"z ->przeciążeniem, by działać jako pobieranie bazy danych, jesteś o wiele bardziej podatny na to, by pozwolić mu przejść, ponieważ koszt operacji nie jest widoczny.
SF.
-2

W jakiś sposób Stack Exchange nie bierze moich innych punktów stosu, więc ... niestety niestety ...

Jednak moim zdaniem druga najczęściej głosowana odpowiedź jest pełna dezinformacji.

Ręcznie rozwijana aplikacja eksperta w C / C ++ ZAWSZE będzie znacznie szybsza niż aplikacja Java, kropka. Nie ma „tak szybkiej jak Java lub Faster”. jest po prostu szybszy, właśnie dzięki przedmiotom, które cytujesz poniżej:

Kompilacja JIT : czy naprawdę spodziewasz się, że automatyczny optymalizator będzie miał mądry programista i zobaczy związek między intencją a kodem, który procesor naprawdę uruchomi ??? Co więcej, wszystko, co robisz, to stracony czas w porównaniu do już skompilowanego programu.

Garbage Collection to narzędzie, które po prostu zwalnia zasoby, których programista zapomniałby zwolnić, w sposób mniej lub bardziej wydajny.

Oczywiście może to być tylko wolniejsze niż to, co zrobiłby ekspert (wybrałeś termin) programista C, aby poradzić sobie z pamięcią (i nie ma przecieków w poprawnie napisanych aplikacjach).

Zoptymalizowana pod kątem wydajności aplikacja C zna procesor, na którym jest uruchomiona, została na niej skompilowana, w przeciwnym razie oznacza to, że nie wykonałeś wszystkich kroków w celu zwiększenia wydajności, prawda?

Statystyka środowiska wykonawczego Jest to poza moją wiedzą, ale podejrzewam, że ekspert w języku C ma więcej niż wystarczającą wiedzę na temat prognozowania gałęzi, aby ponownie przechytrzyć automatyczną optymalizację -

Bardzo dobre biblioteki Istnieje wiele niezoptymalizowanych funkcji, które są łatwo dostępne przez biblioteki w Javie, i to samo dotyczy każdego języka, jednak najbardziej zoptymalizowane biblioteki są napisane w C, szczególnie do obliczeń.

JVM to warstwa abstrakcji, która implikuje zarówno dobre rzeczy, z których wiele jest powyżej, a także sugeruje, że ogólne rozwiązanie jest wolniejsze z założenia.

Ogólny:

Java nigdy nie osiągnie prędkości C / C ++ ze względu na sposób, w jaki działa w JVM z dużą ilością ochrony, funkcji i narzędzi.

C ++ ma wyraźną przewagę w zoptymalizowanym oprogramowaniu, czy to dla komputerów czy gier, i często można zobaczyć, że implementacje C ++ wygrywają konkursy kodowania do tego stopnia, że ​​najlepsze implementacje Java można zobaczyć tylko na drugiej stronie.

W praktyce C ++ nie jest zabawką i nie pozwoli ci uniknąć wielu błędów, z którymi może sobie poradzić większość współczesnych języków, jednak będąc prostszym i mniej bezpiecznym, jest z natury szybszy.

Podsumowując, chciałbym powiedzieć, że większość ludzi nie daje za to dwóch centów, że w końcu optymalizacja jest sportem zarezerwowanym tylko dla bardzo niewielu szczęśliwych twórców i że z wyjątkiem przypadków, w których wydajność naprawdę stanowi problem (Tj. gdzie pomnożenie sprzętu przez 10 nie pomoże - lub reprezentuje co najmniej kilka milionów), większość menedżerów woli niezoptymalizowaną aplikację i masę sprzętu.

Morg.
źródło
Jeszcze raz. Odśmiecanie to nie tylko „narzędzie zwalniające”. GC może zagęścić Twoje struktury. GC może obsłużyć twoje słabe referencje i pomóc ci zrównoważyć buforowanie w ten sposób. Wielostopniowa GC sprawia, że ​​przydzielanie sterty jest znacznie tańsze niż nieporęczne, wolne newlub malloc(). Ogólnie może być znacznie szybsze niż jakiekolwiek ręczne zarządzanie pamięcią - ponieważ nie można ręcznie przenieść obiektów. Całe twoje rozumowanie jest po prostu błędne i stronnicze. Twoja wiedza na temat algorytmów GC i metod optymalizacji JIT jest zbyt ograniczona.
SK-logic
4
Ta odpowiedź jest pełna nieporozumień na temat tego, co mogą zrobić współczesni optymaliści. Ręcznie zoptymalizowany kod nie ma z tym szans. Ale C ++ ma również kompilator optymalizujący.
Konrad Rudolph,
Dzięki za komentarz SK-logika, ale jak to stwierdzicie, GC może być ogólnie znacznie szybsza, mówimy o tym, co będzie najszybsze w konkretnym przypadku, i wydaje się, że większość ludzi zgadza się, że cokolwiek GC może programista może zrobić, a nawet lepiej. Oczywiście możesz przenosić obiekty ręcznie, gdy masz bezpośredni dostęp do pamięci. Lol. Moja wiedza na temat elementów wewnętrznych JVM jest z pewnością ograniczona i spodziewam się, że szefowie Javy pokażą mi światło, a nie tylko powiedzą mi przypadkowe bzdury o tym, że GC jest w stanie robić rzeczy, których nie można zrobić ręcznie (lol ... nawet GC musi skorzystaj z instrukcji procesora;)).
Morg.
Konrad, zgadzam się, że w dużej mierze nie doceniam nowoczesnych optymalizatorów ... uważam jednak za interesujące, że uważasz ręcznie zoptymalizowany kod za gorszy od kodu automatycznie zoptymalizowanego. Czego dokładnie oczekujesz, że kompilator zobaczy, że człowiek nie może?
Morg.
1
Dobrze . naciskaj -1, to nie zmieni faktu, że C ++ jest szybszy niż Java. Mogę nie wiedzieć wiele o współczesnych kompilatorach, ale to nie robi żadnej różnicy w głównej kwestii, która jest poprawna i jest sprzeczna z najczęściej głosowaną odpowiedzią tutaj. Dlaczego inaczej C ++ miałby być priorytetem dla nVidii na ich procesorach graficznych dla HPC. Dlaczego inaczej wszystkie gry byłyby napisane w C ++, dlaczego inaczej każdy silnik DB byłby napisany w C?
Morg.
-4

Widziałem co najmniej dwa imponujące mmo wykonane w Javie, co oznacza, że ​​nie jest wystarczająco szybki do gier, jest błędem. To, że twórcy gier wolą C ++ bardziej niż inne języki, mówi, że nie jest to związane tylko z Javą, oznacza to, że programiści nigdy tak naprawdę nie zajmowali się innymi językami / paradygmatami programowania. Wszystko w dowolnym języku tak zaawansowanym, jak C / C ++, a nawet Java, może wygenerować kod, który technicznie może spełnić lub pokonać argument prędkości. Wszystko, co zostało powiedziane, sprowadza się do tego, co wiedzą programiści, z jakimi zespołami współpracuje większość i co najważniejsze, dlaczego używają wspomnianych narzędzi. Ponieważ zajmujemy się aspektem programowania gier, argumentem musi być coś więcej. Po prostu to powiedz chodzi przede wszystkim o pieniądze i czas dla firmy, która jest martwa na używanie narzędzi, które spełniają wymogi kontroli jakości, aw realnym świecie nie ma żadnego znaczenia z powodu xx powodów wyboru C ++ zamiast Java lub innego języka. To tylko decyzja o masowej produkcji. Na najbardziej podstawowym poziomie algorytmów obliczeniowych, w których bawimy się jedynymi i zerami, argument prędkości jest jednym z najgłupszych argumentów, jakie kiedykolwiek stosowano w grach. Jeśli chcesz tak bardzo przyspieszyć, porzuć całkowicie języki programowania i pracuj z asemblerem, który jest zdecydowanie najlepszą zaletą.

Meh
źródło
2
Ta ściana tekstu nie wydaje się dodawać niczego, co nie zostało jeszcze określone w innych odpowiedziach. Proszę edytować swoją odpowiedź jest bardziej czytelny, i proszę się upewnić, że adresy odpowiedź nie poruszonych przez drugą odpowiedź. W przeciwnym razie zastanów się nad usunięciem odpowiedzi, ponieważ powoduje to tylko hałas w tym momencie.