Czy C++ desktop upadnie?

Czy C++ desktop upadnie?

Wątek przeniesiony 2020-04-16 11:11 z Edukacja przez cerrato.

Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
0

@Krolik:
W zasadzie jedynym popularnym językiem, który ma wbudowanego borrow-checkera w kompilator jest Rust, a z twoich twierdzeń wynika, że bez borrow checkera od razu wpakujemy się w kupę, więc prostym wnioskiem jest to, że każdy język poza Rustem jest badziewiem. Zgadza się?

Rust jest jeszcze za młody, by było w nim naklepane dużo legacy kodu, a jak do tego dojdzie to pewnie poczytamy i krytykę.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
3

Nie. Raczej spodziewam się, że takie rzeczy jak borrow checker będą trafiały do innych języków. Dla C++ już są lintery które sprawdzają czas życia obiektów i referencji.

Po prostu do niedawna uważano, że problemy z pamięcią można rozwiązać tylko przez GC, a żeby mieć dobre GC, to potrzebna jest maszyna wirtualna.
Natomiast teraz Rust pokazał, że w sumie można rozwiązać problemy z pamięcią bez GC, bez maszyny wirtualnej, do tego jeszcze oferując parę innych fajnych cech jak wolność od wyścigów. A wszystko przy świetnej wydajności i niezłej czytelności / ekspresywności kodu. Tym samym jeden z bardzo dużych powodów dla istnienia platform zarządzanych takich jak JVM czy .NET właśnie został unieważniony. Bak GC i brak rozbudowanego runtime'u upraszcza bardzo wiele rzeczy. To nie tylko rozwiązania embedded, ale też choćby możliwość kompilacji na webassembly. Możliwość bezproblemowego wywoływania API systemu i integracja z kodem C / C++ to też bardzo duża rzecz.

Liczę na to, że pociągną to dalej i nawet jeśli sam Rust się nie przyjmie, to że będzie mieć naśladowców. Microsoft zdaje się pracuje nad kolejnym językiem z tej samej kategorii.

Drugim dużym powodem istnienia platform takich jak Java była przenośność, ale... serio, kto używał Javy dla przenośności? Przyjęła się głównie na serwerach, a tam przenośność nie ma żadnego znaczenia bo aplikacje buduje się pod jedną konkretną platformę.

edytowany 5x, ostatnio: Krolik
Zobacz pozostałe 2 komentarze
KR
Natomiast kod typu "dane wchodzą z jednej strony, a wychodzą przetworzone z drugiej strony" pisze się bardzo przyjemnie.
SC
Możesz coś więcej napisać o tym cargo, czy te pakiety są bezpieczne? Ostatnio dużo syfu narobiło się w pakietach do Go, dlatego, że bardzo łatwo je zainstalować w systemie. To samo jest w Ruby i w repozytorium menedżera pakietów RubyGems pomiędzy 16 i 25 lutego zostało udostępnionych 725 bibliotek zawierających szkodliwe oprogramowanie. Jest to już drugi taki atak na programistów Ruby.
SC
W grudniu do PyPI trafiły pliki z nazwami niemal identycznymi do popularnych paczek, np. jellyfish. Phishing homograficzny mógł wówczas skutkować kradzieżą kluczy SSH i GPG z maszyny ofiary. Python i JS/Node tak samo.
siloam
"Dla kogoś, kto kodował w Pythonie zapewne Rust będzie traumatycznym przeżyciem. Dla kogoś kto zna Scalę i C++ będzie jak bułka z masłem." Dla kogoś ktoś zna Scalę i C++ jednocześnie - z naciskiem na C++, bo normalnie w Scali nikt w ręczne zarządzanie pamięcią się nie bawi i przesiadka z Pythona na Scalę wcale nie jest taka trudna -.-
SC
Patrząc po ofertach pracy Scala nie przejęła rynku Javy. Jest za trudna czy jak?
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
0

Drugim dużym powodem istnienia platform takich jak Java była przenośność, ale... serio, kto używał Javy dla przenośności? Przyjęła się głównie na serwerach, a tam przenośność nie ma żadnego znaczenia bo aplikacje buduje się pod jedną konkretną platformę.

Chyba każda korpo udowadnia, że przenośność jest ważna, bo aplikacje biznesowe klepie się na Windowsach, a uruchamia docelowo na Linuksach.

Nie. Raczej spodziewam się, że takie rzeczy jak borrow checker będą trafiały do innych języków. Dla C++ już są lintery które sprawdzają czas życia obiektów i referencji.

Tylko do jakich? Borrow checker w Ruście to w zasadzie formalizacja mechanik z C++a (nawet się trochę przyznali tutaj: https://doc.rust-lang.org/reference/influences.html ), więc dość naturalne, że C++ ma do tego lintery. Względnie mało języków w ogóle polega na czymś takim jak destruktor.

Poza tym myślę, że reactive streams są lepszym rozwiązaniem dla aplikacji biznesowych niż borrow-checker. Borrow-checker może rozwiązywać w pewnym stopniu problem cyklu życia zasobów, ale implementacje reactive streams dodatkowo rozwiązują problem ograniczania zużycia zasobów w danym momencie (by nie wyjść poza limit).


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 5x, ostatnio: Wibowit
Zobacz pozostałe 38 komentarzy
AF
Rozwiązań jest mnóstwo i nie trzeba przesiadać się na notatnik. Jest X11 forwarding, jest XPRA, MS ma Remote Apps, jest RDP, ale to wszystko jest tylko innym opakowaniem pracy zdalnej.
jarekr000000
@Afish: nie wiem nawet co może nie zadziałać w zdalnym debugu javy - robiłem to nawet 20 lat temu, w czasach javy lizanej, o której jeszcze niewiele widziałem (poza tym, że w konstruktorze działają metody wirtualne - pierwsza pułapka po przejściu z C++), IDE wtedy obsysały, a problemem to było odpalanie jvm na kompie z 4mb ramu (takie były serwery).
Wibowit
Jak debugger zatrzyma mi się na breakpoincie i zacznę sobie przeglądać graf dużych obiektów to przy remote debugging całość często się zwiesza.
AF
@jarekr000000: Nie robiłem tego 20 lat temu, za to robiłem to w tym roku i przeglądanie obiektów, robienie kroków, wyliczanie czegoś na boku jest nieludzko wolne, do tego często zdycha i muszę restartować aplikację.
TurkucPodjadek
TurkucPodjadek
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 4 lata
  • Postów:607
2
Krolik napisał(a):

I skoro tak chcieliście kod, to proszę.
W czym ten górny kod (Rust) jest trudniejszy do napisania niż ten dolny (Scala)?

Kopiuj
let collection = vec![0, 1, -59, 2, 4];
println!("Sum of positive elements: {}", collection.iter().filter(|&&item| item > 0).sum());
Kopiuj
val collection = Vector(0, 1, -59, 2, 4)
println(s"Sum of positive elements: ${collection.iterator().filter(_ > 0).sum())}")

Przecież ten kod jest niemal identyczny. Ale nie jest identyczny wydajnościowo.
Ten drugi będzie o rząd wielkości powolniejszy (oczywiście trzeba mierzyć na większych tablicach).

I to jest cały kod biznesowy? Nic więcej nie ma i się nie liczy? Nic więcej znaczenia mieć nie będzie, tylko to, że np. w Scali ten kod będzie wolniejszy niż w Rust, przy pewnych założeniach (dajmy na to, co napisałes)?

I to, jak rozumiem, uderzy w biznes, nie jakiś tam zły marketing (takie "nic" w sumie), nie jakiś tam brak zapotrzebowania na dany software, bo ktoś przestrzelił z pomysłem, nie jakiś tam mały problem typu brak dostępnej bibliotek(i) na teraz, brak dostępnych developerów Rusta (no bo dużo ich!), nie jakies opóźnienia np. na styku z bazą danych (wszakże np. redisy to zbędne wynalazki), tylko taki właśnie mikrobenchmark zadecyduje o być albo nie być, oprogramowania. Zwłaszcza w czasach, kiedy są mikroserwisy, loadbalancery, cache i niech i super ślamazarny soft był w pythonie, co obrabia, nie wiem, w pojedynkę 1 request na sekundę, to jak się postawi dobrze infrastrukture to na "zewnątrz" będzie to wyglądać np. na 1000req/s

Chyba, że jak firmy bedą iść w Rusta, to ich revenue będzie też szedł o rząd wielkości wyżej - jeśli tak jest, to nie martw się, Rust błyskawicznie zdobędzie popularność. Wystarczy, że 1 firma przepisze core na Rusta i poda ile jej to wygenerowało ekstra $ (obojętnie czy oszczędzając sprzęt czy obsługując "więcej")

Także tylko zaznaczam, że patrzenie po wspaniałości języka, po jakimś mikrobenchmarku jest słabe. Kontekst jest ważny. Dla mnie EOT.

KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
4

Wyrywasz mój argument z kontekstu a potem dyskutujesz z czymś czego nie napisałem. Typowy chochoł (straw-man).

Mój kod miał tylko ilustrować, że można mieć wysoką wydajność kodu bez płacenia za to czasem pisania oprogramowania. Te dwie rzeczy są od siebie niezależne. Aby nie było łatwo, wybrałem do porównania język, który uchodzi za jeden z najbardziej ekspresywnych. Mogłem porównać z Javą, ale wtedy by się okazało, że kod Javy jest nie tylko powolniejszy, ale i bardziej skomplikowany.

Argument z brakującą biblioteka jest chybiony, bo brakujące biblioteki są w każdym języku, a z kolei żaden nowy język nie opiera się na bibliotekach tworzonych od zera. Rust ma banalny dostęp do całego ekosystemu C i łatwą integrację z C++. Z punktu widzenia desktopu jest to duży i dojrzały ekosystem. Zwłaszcza że np. inny popularny język, Python, polega na libkach w C++, więc wszystko co masz w Pythonie, jest dostępne też w C++ i Rust, ale nie w Javie (niby da się, ale jest to droga przez mękę).

Natomiast czy wyższa wydajność ma znaczenie biznesowe to osobna kwestia. Znam przypadki z pierwszej ręki gdzie ma. W tej chwili bardzo popularne są rozwiązania chmurowe i mikroserwisy. Pewna znajoma firma robi system zdalnego monitorowania serwerów, którego jedną z funkcji jest zbieranie logów. Pierwsza wersja używała Node.JS. Klienci skarżyli się, że agent zjada im ponad 500 MB. 500 MB na głupiego agenta zbierającego logi to bardzo dużo, jak w chmurze masz instancje z 2 GB na cały system + biznes. Firma przepisała agenta na Rust i zużycie RAMu spadło do 20 MB.

brak dostępnych developerów Rusta (no bo dużo ich!

To jest problem który dotyczy tylko firm klepiących studentami dużo softu niskiej jakości na masę. Ale jeżeli podniesiesz poprzeczkę jakościową (np. wymagasz, aby system webowy otwierał strony w mniej niż 0,1s a nie jak JIRA w 5s), albo robisz oprogramowanie infrastrukturalne (np. system baz danych) czy złożone oprogramowanie desktopowe (np. CAD) to nic Ci po tabunach tanich programistów Pythona, Javy i PHP. Ich ilość tylko utrudnia rekrutację. Liczy się ile jest dobrych programistów.

nie jakiś tam brak zapotrzebowania na dany software, bo ktoś przestrzelił z pomysłem

To jest niezależne od użytej technologii. Równie dobrze możesz przestrzelić używając JS, Javy i Pythona.

Zwłaszcza w czasach, kiedy są mikroserwisy, loadbalancery, cache i niech i super ślamazarny soft był w pythonie, co obrabia, nie wiem, w pojedynkę 1 request na sekundę, to jak się postawi dobrze infrastrukture to na "zewnątrz" będzie to wyglądać np. na 1000req/s

Tak, zaoszczędzić 100k jednorazowo na programiście aby wydać 100k miesięcznie więcej na infrastrukturę. Seems legit.

Te serwery cache i bony na ich utrzymanie to rozumiem rozdają podczas świątecznej promocji w Biedronce za 24,99?

Ciekawe dlaczego Google tak nie robi, tylko woli płacić programistom 40k / miesiąc aby pisali w C++? Mimo, że mieli nawet twórcę Pythona u siebie...

edytowany 6x, ostatnio: Krolik
SC
Kompilator Rust wyłapuje dużo więcej błędów więc powinno to zaoszczędzić dużo dolarów w skali roku. Ten język naprawdę ma potencjał.
KR
Właśnie wczoraj złapał mi błąd, gdzie przekazywałem referencję do obiektu do innego wątku, który mógł żyć dłużej niż obiekt. Normalnie w C/C++/Javie byłby problem.
SC
Polecasz jakieś ide do Rust na debiana i xubuntu?
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
2

Mój kod miał tylko ilustrować, że można mieć wysoką wydajność kodu bez płacenia za to czasem pisania oprogramowania. Te dwie rzeczy są od siebie niezależne. Aby nie było łatwo, wybrałem do porównania język, który uchodzi za jeden z najbardziej ekspresywnych. Mogłem porównać z Javą, ale wtedy by się okazało, że kod Javy jest nie tylko powolniejszy, ale i bardziej skomplikowany.

Mini programiki jednak niewiele pokazują, bo wymagania są mocno abstrakcyjne. Ja mógłbym to zapisać w Javie tak:

Kopiuj
        IntStream stream = IntStream.of(0, 1, -59, 2, 4);
        System.out.println("Sum of positive elements: " + stream.sum());

Działa :)

Dobrym benchmarkiem jest np http://sortbenchmark.org/ - tam nie ma nic na temat szczegółów implementacyjnych w wymaganiach.

W tej chwili bardzo popularne są rozwiązania chmurowe i mikroserwisy. Pewna znajoma firma robi system zdalnego monitorowania serwerów, którego jedną z funkcji jest zbieranie logów. Pierwsza wersja używała Node.JS. Klienci skarżyli się, że agent zjada im ponad 500 MB. 500 MB na głupiego agenta zbierającego logi to bardzo dużo, jak w chmurze masz instancje z 2 GB na cały system + biznes. Firma przepisała agenta na Rust i zużycie RAMu spadło do 20 MB.

Javkę też można odchudzić: https://quarkus.io/#container-first

Ale jeżeli podniesiesz poprzeczkę jakościową (np. wymagasz, aby system webowy otwierał strony w mniej niż 0,1s a nie jak JIRA w 5s),

JIRA zamula, ale raczej przez bazę, a nie przez Javę.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
Zobacz pozostałe 8 komentarzy
nullpt4
nikt nie mówi, że nie :)
Wibowit
A co jest skopanego w equals i hashcode?
PA
a javy nie dało się tak odchudzić, że śmigała na kartach sim? - https://en.wikipedia.org/wiki/Java_Card
KR
equals i hashcode łamie LSP; w praktyce prowadzi to do bugów z porównywaniem obiektów niezgodnych typów - IDEA na szczęście część takich baboli wyłapuje i podkreśla na żywo, ale javac przepuszcza je bez mrugnięcia
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
1

Javkę też można odchudzić: https://quarkus.io/#container-first

No super, jest jeden framework zoptymalizowany na wydajność.

Nie wiem jakim sprzętem testowali, ale patrząc na ich benchmark, to im wyszło że:

  • najbardziej zoptymalizowana natywna wersja REST hello potrzebuje po starcie 12 MB RSS
  • przy 16 wątkach osiąga zawrotne 40k req/s i jest 2x wolniejsza od wersji na JVM, ale niestety wersja na JVM za to wcina 100+ MB.

Teraz porównajmy sobie prosty REST hello na Actix-Web przy 16 wątkach na 3-letnim laptopie:

  • RSS po starcie: 3,8 MB
  • RSS w czasie benchmarku: 6.8 MB
  • throughput: 160k req/s
  • sredni czas odpowiedzi: 0.1 ms
  • czas odpowiedzi 99 percentyl: < 1 ms (program do testów nie podaje lepszej rozdzielczości)

Niestety nie opublikowali najważniejszego parametru, czyli opóźnień - jestem ciekaw jak ich natywne GC sobie radzi, ale najlepsze GC w klasie JVM na razie nie schodzi poniżej 10 ms ;)

edytowany 3x, ostatnio: Krolik
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
1

Jak sobie popatrzę na hello worldy na https://www.techempower.com/benchmarks/ to Javie wcale nie brakuje 5x do Rusta.

Zresztą w benchmarkach Quarkusa wychodzi im max ponad 120k req/s na starym Xeonie:
https://github.com/johnaohara/quarkus-iothread-workerpool/tree/1.3.1.Final


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
2

Zresztą w benchmarkach Quarkusa wychodzi im max ponad 120k req/s na starym Xeonie

Porównujesz serwerowy Xeon z procesorem laptopowym z TDP 45W? Serio?
Do tego te 120k to jest przy zużyciu pamięci 100+ MB.
Moje 160k na laptopie jest przy zużyciu < 7 MB.

Nadal to jest miażdżąca przewaga kodu kompilowanego statycznie w szybkim języku (to czy to jest Rust, nie ma dużego znaczenia, bo w C++ byłoby tak samo).

I teraz wracając do tematu na serwerze oczywiście te 100 MB vs 7 MB może nie mieć znaczenia, ale już na desktopie lub na smartfonie taka różnica będzie decydowała o tym, ile system uśpi Ci aplikacji w tle. Ubijanie aplikacji w tle jest dość poważnym problemem Androida (zarazem napędzającym sprzedaż telefonów z 6 GB RAM i więcej).

Nawet jeśli Javę da się jakoś odchudzić, to naprawdę - nie widzę powodu po co tak się męczyć? Po co projektować trudny do optymalizacji język i potem walczyć przez 30 lat aby zrobić jako-tako wydajny runtime / system kompilacji do niego, kiedy można po prostu pisać w C++ x20 / Rust / Swift i mieć porządną wydajność i pełną kontrolę od początku bez kombinowania? W latach 90-tych i pierwszej dekadzie 2000 miało to sens, bo segfaulty w C++ z klasami, a Swifta/Rusta nie było. Teraz mamy C++x20 + lintery, Rust, Swift (oba bezpieczne i kompilowane statycznie) i takie kombinowanie dla mnie nie ma sensu.

edytowany 3x, ostatnio: Krolik
siloam
"Porównujesz serwerowy Xeon z procesorem laptopowym z TDP 45W? Serio?" Nie. W benchmarku TE Rust dostał taką samą maszynę i jakoś nie widać znacznej przewagi. Kod Javy jest o wiele krótszy, a przez to łatwiejszy w utrzymaniu. Teraz czas programisty jest droższy niż sprzęt. Z tym nie pohandlujesz.
KR
Benchmarki TE mają od spodem bazę danych - postgres, więc to mocno je wyrównuje. Po drugie kod Javy nie jest krótszy kodu Rust. Na ogół jest odwrotnie - Rust jest bardziej abstrakcyjny. Np. jeśli Java ma być w miarę wydajna, to nie możesz używać np. strumieni, lambda, polimorfizmu, refleksji. Natomiast w Rust możesz.
KR
Poza tym dlaczego zawsze pracujecie zużycie CPU a nie pamięć? Użycie kilku-kilkunastu MB zamiast kilkuset to "nie ma prawie żadnej przewagi"?
WeiXiao
@Krolik: Poza tym dlaczego zawsze pracujecie zużycie CPU a nie pamięć? procesory są relatywnie drogie oraz ciepło :P
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
1

Podaj architekturę procka i średnie taktowanie podczas testu.

Nawet jeśli Javę da się jakoś odchudzić, to naprawdę - nie widzę powodu po co tak się męczyć? Po co projektować trudny do optymalizacji język i potem walczyć przez 30 lat aby zrobić jako-tako wydajny runtime / system kompilacji do niego, kiedy można po prostu pisać w C++ x20 / Rust / Swift i mieć porządną wydajność i pełną kontrolę od początku bez kombinowania? W latach 90-tych i pierwszej dekadzie 2000 miało to sens, bo segfaulty w C++ z klasami, a Swifta/Rusta nie było. Teraz mamy C++x20 + lintery, Rust, Swift (oba bezpieczne i kompilowane statycznie) i takie kombinowanie dla mnie nie ma sensu.

Masę energii i pieniedzy zainwestowano zarówno w Javę jak i w GCC, LLVM, itp itd Inwestowanie w Javę ma sens, bo jest masa programistów Javy, masa kodu Javowego, więc ulepszenia w Javie wpływają na dużą część rynku. Rust dalej jest w fazie "inflated expectations" z https://en.wikipedia.org/wiki/Hype_cycle i nie wiadomo w jakim stopniu zawojuje rynek i na ile opłaca się w niego inwestować.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
Zobacz pozostałe 9 komentarzy
Wibowit
Popatrz sobie na https://en.wikipedia.org/wiki/MAJC - to miał być wydajny procek, a jego instrukcje są totalnie odmienne od bajtkodu, nawet bardziej niż typowe x86 czy ARM.
Wibowit
A skąd jest to 4x? Porównujesz jakieś przypadkowe wartości pewnie.
KR
Porównuje wydajność na swoim laptopie z wydajnością podaną na stronie Quarkusa, którą podlinkowałem. Moja wydajność jest na pewno zaniżona, bo testuję programem aby, który zjada cały jeden rdzeń. A powinienem go odpalić na innej maszynie.
KR
Abstrahując nawet od moich wyników, na ich stronie wyraźnie widać, że Java przejechana AOTem jest 2x powolniejsza niż na JVM. A Java na JVM w większości mikrobenchmarków jest 2-3x powolniejsza od kodu C i C++. Do tego mikrobenchmarki zawyżają wydajność Javy, bo nie są pisane idiomatycznie, a koszt abstrakcji Javowych jest wyższy od kosztu abstrakcji C++ / Rust.
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
1

https://quarkus.io/blog/runtime-performance/

Tu podają przynajmniej czasy odpowiedzi. Masakra.
20x powolniej. To też pewnie zasługa mojego wyższego taktowania?

Niemniej, wątek jest o desktopie i wolałbym zobaczyć jakieś porównania może np. responsywności JavaFX vs GTK (w C, C++ lub Rust) vs QT. To byłoby bardziej na temat. :D
A zwłaszcza sytuacje takie jak otwierasz nowy dialog-box i on oczywiście musi zaalokować ileś pamięci na nowe kontrolki a wtedy akurat zwykle wcina się GC, więc okienko zobaczysz dopiero jak GC się skończy.

edytowany 3x, ostatnio: Krolik
SC
Powstaje podobno fork biblioteki Qt w Rust, twórcy Plasmy i niezależni programiści już go tworzą, czytając komentarze z phoronix.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
1

Częściej freezuje mi się Excel i Outlook niż IntelliJ mimo iż IntelliJa znacznie intensywniej używam. Na przycinanie GUI ma wpływ głównie nie GC, a kwiatki typu pełniaKsiężyca.await() albo przemielJakNajszybciejPięćGigaDanych() w wątku GUI, które (jeśli już muszą być) to powinny siedzieć w osobnych wątkach.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4709
1

Dokładnie jest jak pisze wibowit, gc javowym UI to był problem 20 lat temu. Problemem jest natomiast to, że większość programitów UI nigdy nawet podstawowej dokumentacji nie przeczytała o good practices w UI.
GC natomiast - to jest nadal problemem w grach 3d/fps. I dlatego (między innymi) raczej ich się nie robi w javie.

Jestem zszokowany, że w javowego minecrafta da się grać i to nawet w VR, gdzie każda przycinka to potencjalna migrena / wymioty dla gracza.
Aczkolwiek sądze, że ludzie to tunujący do wersi używalnej gdzieś w pewnym momencie pomyśleli, że być może gdyby nie mieli gc byłoby w sumie mniej pracy....


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 5x, ostatnio: jarekr000000
Zobacz pozostałe 20 komentarzy
Sunnydev
@Azarien: jak masz java edition, to bedrock masz za darmo, a co to prawdziwości, to kłóciłbym się. @jarekr000000: oczywiście wyolbrzymiam, ale na starszych/słabszych urządzeniach różnica wzrasta, a tam gdzie java edition nie działa, bedrock daje radę.
Azarien
No właśnie nie mam Bedrocka za darmo. Tak było kiedyś, od niedawna tak nie jest.
Sunnydev
@Azarien: właśnie to jest problem bedrock edtion, że ludzie przywykli do tej javowej wersji i tam jest niemal wszystko - serwery, pluginy, mody itp, a na bedrock jeszcze bida.
Sunnydev
@Azarien: naprawdę? ale lipa w takim razie.
Azarien
No więc skoro „wszyscy” grają na Javie, a za Bedrock musiałbym zapłacić drugie tyle, to podziękuję. Nie twierdzę że Bedrock jest zły, ale polityka producenta w tej kwestii jest dla mnie niezrozumiała.
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
1

GC nadal jest problemem. Wyjdziesz na swap i pozamiatane. Natomiast aplikacja natywna po wyjściu na swap działa nadal przyzwoicie, bo zwykle nie ma potrzeby przeglądania całej sterty na raz jak to robi GC. OS nie wie o tym, że aplikacja używa GC i może sobie dowolnie ją wymieść na swap, nawet jeśli pamięci jest wystarczająco dużo.

Dlatego Cassandra na początku woła mlockall, z dobrym efektem dla siebie ale złym dla pozostałych procesów.

Często opłaca się wywalić na swap rzadko używaną pamięć po to aby mieć jej więcej na obiekty często u używane.

edytowany 4x, ostatnio: Krolik
SC
Przy 8GB RAM nie jest potrzebny swap dla przeciętnego kowalskiego z Ubuntu? Piszesz o produkcji, swap na serwerze, czy pracy na desktopie jakiejś wydajnej obróbce graficznej, gdzie może zabraknąć pamięci?
KR
Swap jest użyteczny nawet jak masz pod dostatkiem pamięci. Pozwala uwolnić więcej pamięci na cache. Nie ma sensu marnować pamięci na dane i kod, do których dostęp jest bardzo rzadki.
SC
Ale jak mam dysk ssd ale laptop jest stary z wejściami sata2 to nie wykorzysta pełnej szybkości dysku czyli 550MB/s i odwoływanie się do swap będzie spowalniało system i użycie dysku?
KR
Ale to właśnie po to system wyrzuca na dysk dane, z których korzystasz rzadko, aby w pamięci trzymać te które są używane często. GC to psuje okresowo dotykając wszystkich danych, nawet jeśli nie są używane.
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:8 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
2
Krolik napisał(a):

GC nadal jest problemem. Wyjdziesz na swap i pozamiatane. Natomiast aplikacja natywna po wyjściu na swap działa nadal przyzwoicie, bo zwykle nie ma potrzeby przeglądania całej sterty na raz jak to robi GC.

Hm, czy Go jest według Ciebie językiem natywnym?


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
KR
Discord ostatnio zrezygnował z Go na rzecz Rusta właśnie przez GC. Go to trochę taka Java w innym wcieleniu.
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4709
1
Krolik napisał(a):

GC nadal jest problemem. Wyjdziesz na swap i pozamiatane. Natomiast aplikacja natywna po wyjściu na swap działa nadal przyzwoicie, bo zwykle nie ma potrzeby przeglądania całej sterty na raz jak to robi GC. OS nie wie o tym, że aplikacja używa GC i może sobie dowolnie ją wymieść na swap, nawet jeśli pamięci jest wystarczająco dużo.

Captain obvious przypomina: GC zwykle nie musi przeglądać całej sterty. Od algorytmu GC zależy jak często, ale przeglądanie całej sterty to jest zwykle opcja ostateczna i praktycznie każde GC stara sie to minimalizować (różnie to oczywiście wychodzi - zależy to od programu i od GC).
Poza tym czasy, że obiekty rzeczywiście lądowały na stercie powoli się kończą - z każdym nowszym wcieleniem graala jednak więcej ląduje na stosie (escape analysis) i w stertę trafia to co faktycznie żyje trochę dłużej. (ten feature akurat ostatnio testowałem).


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 4x, ostatnio: jarekr000000
KR
Oczywiście że każde GC stara się zminimalizować skanowanie starszej generacji, bo jest to bardzo droga operacja, ale nie da się tego wyeliminować. Nie da się, bo zawsze jakieś obiekty będą żyły dłużej i trzeba je upchać do tenured. GC nadal nie działa dobrze dla aplikacji z dużym cache, bo dla cache "generational hypothesis" jest fałszywa. Większość obiektów żyje długo.
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
3

Uniknąć przeglądania całej sterty się nie da.
Można to tylko opóźnić. Opóźnianie polega zwykle na przydzieleniu bardzo dużo pamieci dla młodej generacji, na tyle dużo, aby większość obiektów umarło zanim zostaną wypromowane. Drugim sposobem jest oczywiście odpowiednio większa cała sterta. Teraz już wiecie dlaczego aplikacje zarządzane potrzebują 10x więcej RAMu niż natywne.

Ale tak czy inaczej przeglądanie całej sterty zawsze nastąpi. I jeśli jej część została wyrzucona na swap to będzie wyraźna zawieszka.

edytowany 1x, ostatnio: Krolik
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4709
2

Z powodu jak powyżej powstał Shanondoah GC, który nie jest generacyjny, a wydajne duże cache to jeden z obsługiwanych przypadków.
Chyba też ZGC ma podobne właściwości (ale ten znowu zupełnie zapomniałem jak działa :/ )
Oczywistą wadą jest to, że aplikacja musi się zdecydować na jeden gc, więc aplikacja, która przez 2 godziny jest 100 Gb cache, a przez następne 2 godziny będzie przetwarzać jakieś batche (i potencjalnie będzię generational friendly) to nie jest idealny dla JVM przypadek.

Zresztą ta globalność i duża ilość opcji JVM to akurat jest problem. W benchmarku zwykle da się przytunować nieźle (choć czasem w nieoczywisty sposób :/). Tunowanie jvm (szczególnie gc) w rzeczywistej, zmieniającej się aplikacji to czarna magia (na szczęście 99% aplikacji ten problem nie dotyczy).

Zresztą jeśli chodzi o SWAPowanie (gdzieś były komentarze jak to GC przeszkadza...) to akurat posiadanie GC jest często dość dobrym pomysłem - w szczególności kompaktującego GC!


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 4x, ostatnio: jarekr000000
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
1

Zarówno Shenandoah, ZGC jak i G1 muszą przeglądać całą stertę.

Innowacja nie polega na braku przeglądania całej sterty a na braku konieczności defragmentacji całej sterty. Zamiast tego one defragmentują po kawałku, regionami.

Jeżeli nigdy byś nie przeglądał całej sterty, to nie zidentyfikowałbyś które obiekty są używane, a które nie.

Jak już jesteśmy przy GC o niskich opóźnieniach to należy wspomnieć, że te GC mają 2-3x niższą przepustowość niż klasyczne blokujące GC, a mimo to nie dają żadnych gwarancji na pauzy.

Nasi klienci używają G1 na produkcji i zwykle wszystko jest ok dopóki obciążenie jest małe. Przychodzi czarny piątek, obciążenie rośnie, GC przestaje wyrabiać i nagle się pojawiają pauzy, bo nagle okazuje się że szybkość sprzątania jest mniejsza niż szybkość generowania nowych śmieci.

Zresztą jeśli chodzi o SWAPowanie (gdzieś były komentarze jak to GC przeszkadza...) to akurat posiadanie GC jest często dość dobrym pomysłem - w szczególności kompaktującego GC!

Jest bardzo złym pomysłem, bo nie masz żadnego wpływu na to jak GC ułoży obiekty w pamięci. W C++ moge zrobić osobne sterty i mam gwarancję że nic się nie pomiesza.

edytowany 6x, ostatnio: Krolik
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4709
1
Krolik napisał(a):

Zarówno Shenandoah, ZGC jak i G1 muszą przeglądać całą stertę.

Innowacja nie polega na braku przeglądania całej sterty a na braku konieczności defragmentacji całej sterty. Zamiast tego one defragmentują po kawałku, regionami.

Tu masz rację zapędziłem się.

Jeżeli nigdy byś nie przeglądał całej sterty, to nie zidentyfikowałbyś które obiekty są używane, a które nie.

W teorii nie trzeba. GC w GHC tego nie robi. Nie trzeba łazić po "niezmienionych starych" przy wywalaniu nowych. Generacyjny kolektor, który potrafi odróżnić obiekty niemutowalne (np, dzięki write barrier ) mógłby z tego skorzystać. Ale prawda jest taka, że nie znalazłem, żeby któryś javowy to naprawdę robił (są "legendy", ale nie znalazłem konkretów).

Ogólnie - jesteśmy przy desktopie C++, a dyskutujemy GC w JVM i to coraz bardziej niestandardowe przypadki, gdzie GC może bardziej przeszkadzać niż pomagać. Tak są takie przypadki - nawet spotkałem w swoim życiu.
Tylko, że to naprawdę bardzo skromny procent aplikacji i prawie w ogole problem nie dotyczy desktopa. Najbliżej desktopu to w grach fps jest problem z GC. A Java ma nawet większy i nie dlatego, że jest sama w sobie wolna, ale dlatego że korzysta głównie ze starego opengl (przenośność) i to jeszcze poprzez JNI :-(

W normalnym desktopie, ani jvm ani GC nie są żadnym problemem.
Dawno temu jvm miał problem z powolnym wstawaniem więc zrobienie czegoś prostego w stylu notatnika w javie to był absurdalnie nieżyciowy pomysł (seej Edit). Ale te czasy już minęły.


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 5x, ostatnio: jarekr000000
tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
5

Jeśli komuś nie chce się czytać ośmiu stron dyskusji to podaję streszczenie:
"Jak dzielnie Java walczy z problemami które sama sobie stworzyła"


"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
AF
Wartościowe jest to, że JVM pokazał, iż wiele z tych problemów da się rozwiązać.
SC
C# wygrało na desktopie z Javą?
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
2
tajny_agent napisał(a):

Jeśli komuś nie chce się czytać ośmiu stron dyskusji to podaję streszczenie:
"Jak dzielnie Java walczy z problemami które sama sobie stworzyła"

Nie. Java to tylko przykład. Tak naprawdę dyskusja to Rust/ C++ vs reszta świata. Reszta świata ma te same niby problemy (?) co Java czyli brak destruktorów odpalających się tuż po wyjściu obiektu poza zasięg i/ lub brak w pełni działającej kompilacji AOT. Przykłady języków z tymi problemami to: C, Java, C#, Python, JavaScript, PHP, Go, Haskell, itp itd


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
Zobacz pozostałe 14 komentarzy
jarekr000000
@Wibowit: ciekawe, bo widać, że kod jest już nieźle zoptymalizowany i dość benchmarkowy - powinno wyjść inaczej :-)
nullpt4
Z drugiej strony niemutowalnosć pociąga za sobą tworzenie większej ilości śmiecia,to niekoniecznie jest prawda,to tak faktycznie działa w Javie i innych side effects languages,ale w pure te operacje są zoptymalizowane,i jeśli modifikujesz liste która ma 1000 elementów,np dodajesz element-to w pamięci jest "nowa" lista która składa się ze starej+jeden element-czyli nie tworzysz całkowicie nowej listy,tylko reuzywasz obiektów które są już w pamięci.A w przypadku takiej npJavy faktycznie by było stworzyć całkowicie nową listę z 1001 elementów -nie ma machanizmu reużywania.
Wibowit
To że standardowe kolekcje Javy nie nadają się do FP nie oznacza że takich w ogóle nie ma. Do Javy jest vavr.io, Scala ma własne implementacje kolekcji, implementacje Haskella na JVM też raczej mają własne kolekcje, itd
nullpt4
Ok, jeśli tam też jest zaimplementowany ten mechanizm reużywania czego tylko się da, to spoko :P
Wibowit
Listy wiązane pojedynczo to najprostszy przypadek i to jest ogarnięte raczej we wszystkich funkcyjnych kolekcjach. Większym problemem są drzewiaste struktury, gdzie to reużywanie jest trudniejsze, bo wymaga wykrywania niezmienionych poddrzew.
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4709
1

@Wibowit - Swift jest ciekawy, bo bazuje na reference counting - jak dla mnie bardzo nietypowe posunięcie, dziwne. Myślałem że wiadomo, że to nie działa :-) ale z drugiej strony dobrze, że ktoś robi eksperymenty.


jeden i pół terabajta powinno wystarczyć każdemu
Zobacz pozostałe 17 komentarzy
PA
@Krolik: w haskellu niekoniecznie wymieniasz niemutowalne struktury między wątkami. STM to dość popularne rozwiązanie.
jarekr000000
@part - może i popularne - ale nie mam pojęcia jak w tym przypadku zachowuje się GC - nie zdziwiłbym się jakby była tam niezła czarna magia, niekoniecznie wydajna. Ale kod jest można poszukać.
AF
@jarekr000000: Jeżeli używasz specjalnego typu wskaźnika/referencji, to już polegasz na konkretnej implementacji. Czy to jest problem, to zależy od aplikacji, używanie stringów też łamie DI, ale bardzo rzadko jest to problem. Gorsza sprawa, gdy explicite wołasz delete, wtedy kod jawnie pokazuje tę zależność (wprawdzie kompilator może ją wywalić, ale wtedy wiążemy się do środowiska uruchomieniowego z konkretną ideą alokacji pamięci).
SC
Scala, Rust i Swift to dobry wybór gdy szukasz jakiegoś nowoczesnego języka programowania. Z tych wszystkich nowych języków które powstają są ponoć najlepiej zaprojektowane.
tajny_agent
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:1340
2
Wibowit napisał(a):

Nie. Java to tylko przykład. Tak naprawdę dyskusja to Rust/ C++ vs reszta świata.

To co się rzuca w oczy w każdym kolejnym poście to Java/JVM/GraalVM/GC/etc. Co to ma wspólnego z C++ i czy tak wygląda dyskusja C++/Rust vs reszta świata? No wątpię ;)

Zarzut: GC zamula! - ojej, ale mamy już fyfnastą implementację i ona jest super!
Zarzut: apka wolno startuje - ale stworzyliśmy native-image i kompiluje się do natywnego kodu, działa szybko!
Zarzut: wszystko ląduje na stercie - ale GraalVM robi czary-mary i przerzuca co trzeba na stos!

Przyznam szczerze, że trochę nie rozumiem takiego podejścia. Zamiast bronić Java-style to na siłę próbujesz/próbujecie udowodnić, że już chwilka, momencik i będziemy jak C++.
Po co?


"I love C++. It's the best language in the world right now for me to write the code that i need and want to write"
~ Herb Sutter
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:8 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
1
tajny_agent napisał(a):
Wibowit napisał(a):

Nie. Java to tylko przykład. Tak naprawdę dyskusja to Rust/ C++ vs reszta świata.

To co się rzuca w oczy w każdym kolejnym poście to Java/JVM/GraalVM/GC/etc. Co to ma wspólnego z C++ i czy tak wygląda dyskusja C++/Rust vs reszta świata? No wątpię ;)

Zarzut: GC zamula! - ojej, ale mamy już fyfnastą implementację i ona jest super!
Zarzut: apka wolno startuje - ale stworzyliśmy native-image i kompiluje się do natywnego kodu, działa szybko!
Zarzut: wszystko ląduje na stercie - ale GraalVM robi czary-mary i przerzuca co trzeba na stos!

Przyznam szczerze, że trochę nie rozumiem takiego podejścia. Zamiast bronić Java-style to na siłę próbujesz/próbujecie udowodnić, że już chwilka, momencik i będziemy jak C++.
Po co?

Żeby nie mieć wycieków pamięci i nie musieć się uczyć o wiele bardziej skomplikowanej składni języka C++


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
KR
C++ ma wiele za uszami, ale Java też nie jest już taka prosta jak kiedyś. Wycieki pamięci od C++x11 to raczej rzadkość.
nullpt4
IMHO ten argument przestał być prawdziwy już 10 lat temu z wejściem smart pointerów, ale ludzie będą go przytaczać już do końca świata :P
KR
W ogóle nawet same smart pointery to często przesada. Jestem w szoku ile rzeczy daje się zrobić zwykłym unique_ptr (a w Rust zwykłym przesuwaniem wartości). Taki kod jest zwykle bardzo prosty. Natomiast jeśli ktoś potrzebuje GC, to zapewne robi coś bardzo skomplikowanego i mnie się źle pracuje z takim kodem.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
1

@tajny_agent:
Czym jest Java-style, żeby tego bronić i po co?

Jakbyś się wczytał to byś zauważył, że jedynym argumentem Krolika który się ostał jest kwestia deterministycznych destruktorów. Są one tylko w C++, Ruście + może jakichś mniej znanych językach, natomiast reszta świata tego nie ma. Krolik ma nadzieję, że:

Raczej spodziewam się, że takie rzeczy jak borrow checker będą trafiały do innych języków.

Borrow checker jest tylko w Ruście i linterach do C++. Jaka jest szansa, że borrow checker wejdzie do innych języków (tych, ktore nie polegają teraz na destruktorach) i będzie miał te same zalety co w Ruście? Dalej to nie wygląda na wojnę Rust/ C++ vs reszta świata? Zamiast Javy można podstawić Haskella, Go, JavaScript, itd i zarzuty będą te same.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 2x, ostatnio: Wibowit
KR
Jest też w Verona od MS.
Wibowit
Zalicza się do mniej znanych.
BraVolt
  • Rejestracja:prawie 6 lat
  • Ostatnio:prawie 4 lata
  • Lokalizacja:Warszawa
  • Postów:2918
2
tajny_agent napisał(a):

To co się rzuca w oczy w każdym kolejnym poście to Java/JVM/GraalVM/GC/etc.

Każda dostatecznie długa dyskusja zejdzie albo na Java albo na Linux.


"Kiedy wiedzieć czy zacząć nauke Springa? bo w czystej Javie to nic ciekawego nie zrobie chyba"
Ein Volk, ein Reich, ein Kwa-Kwa ***** ***
edytowany 1x, ostatnio: BraVolt
Shalom
Jakby się dało wydzielać wątki, to bym to uczynił bo jest tu ciekawa dyskusja na temat pamięci, o tyle ciekawsza że biorą w niej udział ludzie którzy trochę się na tym nawet znają. Niestety kojot nie wspiera takich czarów :(
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 9 godzin
2

Zrobiłem benchmarki malloc vs GC Javowe bazując na najszybszych programach z https://benchmarksgame-team.pages.debian.net/benchmarksgame/performance/binarytrees.html które nie stosują pul obiektów (zmodyfikowałem kod Javowy by wypisywał rodzaje GC):

Kopiuj
:/tmp/binary-trees$ ~/devel/jdk-14.0.1+7/bin/java -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -version
openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 14.0.1+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 14.0.1+7, mixed mode, sharing)
:/tmp/binary-trees$ ~/devel/jdk-15/bin/java --version
openjdk 15-ea 2020-09-15
OpenJDK Runtime Environment (build 15-ea+20-899)
OpenJDK 64-Bit Server VM (build 15-ea+20-899, mixed mode, sharing)
:/tmp/binary-trees$ gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
:/tmp/binary-trees$ g++ --version
g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
:/tmp/binary-trees$ /usr/bin/gcc -pipe -Wall -O3 -fomit-frame-pointer -march=core2 -pthread c-gcc-5.c -o c-gcc-5.run
:/tmp/binary-trees$ /usr/bin/g++ -c -pipe -O3 -fomit-frame-pointer -march=core2 cpp-gpp-2.cpp -o cpp-gpp-2.o
:/tmp/binary-trees$ /usr/bin/g++ cpp-gpp-2.o -o cpp-gpp-2.run
:/tmp/binary-trees$ javac -d . binarytrees.java

:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ./c-gcc-5.run 21
	Elapsed (wall clock) time: 0:05.90
	Maximum resident set size (kbytes): 351424
:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ./cpp-gpp-2.run 21
	Elapsed (wall clock) time: 0:12.08
	Maximum resident set size (kbytes): 265664

:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ~/devel/jdk-15/bin/java -Xmx500M -XX:+UseG1GC binarytrees 21
G1 Young Generation
[G1 Eden Space, G1 Survivor Space, G1 Old Gen]
G1 Old Generation
[G1 Eden Space, G1 Survivor Space, G1 Old Gen]
	Elapsed (wall clock) time: 0:03.36
	Maximum resident set size (kbytes): 578732
:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ~/devel/jdk-15/bin/java -Xmx500M -XX:+UseParallelGC binarytrees 21
PS MarkSweep
[PS Eden Space, PS Survivor Space, PS Old Gen]
PS Scavenge
[PS Eden Space, PS Survivor Space]
	Elapsed (wall clock) time: 0:03.56
	Maximum resident set size (kbytes): 535872
:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ~/devel/jdk-15/bin/java -Xmx500M -XX:+UseZGC binarytrees 21
ZGC
[ZHeap]
	Elapsed (wall clock) time: 0:13.06
	Maximum resident set size (kbytes): 1528744
:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ~/devel/jdk-14.0.1+7/bin/java -Xmx500M -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC binarytrees 21
Shenandoah Pauses
[Shenandoah]
Shenandoah Cycles
[Shenandoah]
	Elapsed (wall clock) time: 0:12.42
	Maximum resident set size (kbytes): 467780

:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ~/devel/jdk-15/bin/java -Xmx300M -XX:+UseParallelGC binarytrees 21
PS MarkSweep
[PS Eden Space, PS Survivor Space, PS Old Gen]
PS Scavenge
[PS Eden Space, PS Survivor Space]
	Elapsed (wall clock) time: 0:06.03
	Maximum resident set size (kbytes): 352524
:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ~/devel/jdk-15/bin/java -Xmx300M -XX:+UseG1GC binarytrees 21
G1 Young Generation
[G1 Eden Space, G1 Survivor Space, G1 Old Gen]
G1 Old Generation
[G1 Eden Space, G1 Survivor Space, G1 Old Gen]
	Elapsed (wall clock) time: 0:06.05
	Maximum resident set size (kbytes): 367740
:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ~/devel/jdk-15/bin/java -Xmx300M -XX:+UseZGC binarytrees 21
ZGC
[ZHeap]
	Elapsed (wall clock) time: 0:21.84
	Maximum resident set size (kbytes): 934152
:/tmp/binary-trees$ /usr/bin/time -f "\tElapsed (wall clock) time: %E\n\tMaximum resident set size (kbytes): %M" ~/devel/jdk-14.0.1+7/bin/java -Xmx300M -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC binarytrees 21
Shenandoah Pauses
[Shenandoah]
Shenandoah Cycles
[Shenandoah]
	Elapsed (wall clock) time: 0:25.32
	Maximum resident set size (kbytes): 333436

Wartości zajętości pamięci dla ZGC są przekłamane, bo ZGC wielokrotnie mapuje te same obszary pamięci, a kalkulatory zajętości pamięci tego nie rozpoznają. Jak widać zarówno czasy jak i zajętość pamięci są konkurencyjne dla C i C++.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około 16 godzin
  • Postów:2964
0

Czyli wykazałeś to co pisałem nas początku, że alokacja Javy jest co najwyżej tak samo wydajna jak malloc, przy założeniu że mamy duży nadmiar wolnej sterty. Przy czym nadal masz kilka problemów z tym benchmarkiem:

  1. porównywałeś na domyślnym alokatorze z glibc. A można było użyć jemalloc albo tcmalloc, które uchodzą za szybsze
  2. JVM oszczędza dużo czasu na prealokowaniu pamięci z systemu przy starcie. Alokatory natywne natomiast żądają kolejnych stron w miarę rosnącego zużycia. Jeśli ten benchmark jedyne co robi to jednorazowo alokuje dużą liczbę obiektów, to oczywiste jest, że domapowywanie kolejnych stron przyrostowo będzie mieć większy narzut. JVM zna docelową ilość pamięci, programy w C++ nie.
  3. Testujesz jeden bardzo specyficzny schemat alokacji. Trudno ekstrapolować to na inne przypadki.
  4. GC Javy w ogóle się wyłączył choć raz? ;)

Natomiast takie porównanie jest oczywiście i tak bez sensu, bo programy w C++ / Rust alokują na stercie znacznie mniej niż JVM, więc nawet jeśli malloc/new byłoby 2x wolniejsze w C++ to i tak C++ ma dużą przewagę. W C++ można pisać programy całkowicie bez użycia sterty. Tam gdzie alokacja zajmuje za dużo czasu, to się robi pulę / arenę. Tak jak w benchmarkach, które celowo wyrzuciłeś.

No i Shenandoah i ZGC jednak przegrały ten benchmark pod względem zajętości pamięci i czasu wykonania.

edytowany 2x, ostatnio: Krolik
WeiXiao
  • Rejestracja:około 9 lat
  • Ostatnio:około 2 godziny
  • Postów:5145
1

@Krolik:

Nawet jeśli Javę da się jakoś odchudzić, to naprawdę - nie widzę powodu po co tak się męczyć? Po co projektować trudny do optymalizacji język i potem walczyć przez 30 lat aby zrobić jako-tako wydajny runtime / system kompilacji do niego, kiedy można po prostu pisać w...

honestly? gdybyś tutaj nie wstawił javy, to bym pomyślał że piszesz o C++

dekady puchnięcia języka którego parsowanie to wyzwanie samo w sobie i dziesiątki MILIONÓW linii kodu kompilatora mielącego nieprawdopodobnie długo (z mojej perspektywy) i próbowanie obsługiwać coraz więcej możliwych rzeczy do policzenia podczas kompilacji.

W VSCode wpisywanie literek potrafi lagować!

to ja zapytam, a jaki kod trzeba było parsnąć pod spodem gdy wpisywałeś te literki? ;)

edytowany 7x, ostatnio: WeiXiao
Zobacz pozostałe 6 komentarzy
vpiotr
C++ ze swoja biblioteka puchnie juz od jakiegos czasu. Jak czytam nowinki np. o pralni (std::laundry) to sie zastanawiam czy ten jezyk nadal jest dla ludzi czy raczej dla maszyn ktore czasem ten kod udostepniaja ludziom (parafraza).
KR
C++ ma system budowania z poprzedniej epoki. Jest to w sumie jedna z większych rzeczy, która mi w nim przeszkadza. Jednak mimo długich czasów budowania kod wynikowy może być bardzo dobry i raczej C++ nie przeszkadza w generowaniu wydajnego kodu tak jak przeszkadza Java. Java wymusza używanie kosztownych mechanizmów i liczy na to, że dostatecznie dobry JVM wyeliminuje narzut. Co po 25 latach na razie udaje się ze średnim skutkiem. Programista nawet nie może z tych rzeczy zrezygnować. W C++ natomiast użycie kosztownych mechanizmów jest zawsze wyborem programisty.
nullpt4
@vpiotr: mi się tam podobają nowe funkcjonalności w std:: razem z lambdami, ranges i algorytmami. Wreszcie można pisać kod bardziej deklaratywny :P
WeiXiao
pracowałem w projekcie gdzie było 2mln lini kodu w C++ i projekt budował się pare min. spróbuj zbudować llvma :-)
nullpt4
@WeiXiao: cmake .. ; time make -j16 ~ 21 minut, 5.4 mln loc. Ale dalej nie wiem jak można było pomylić z opisu Krolika Jave z C++ ;/

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.