Czy C++ desktop upadnie?

Czy C++ desktop upadnie?

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

Patryk27
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:prawie 2 lata
  • Lokalizacja:Wrocław
  • Postów:13042
0

Wszystko naklepałem w python

Qt, OpenCV i Tensorflow (czy co tam wykorzystywałeś pod spodem) są napisane w C/C++, zatem w Pythonie najwyżej spiąłeś wysokopoziomową logikę, a nie "klepnąłeś wszystko".

To trochę jak gdyby stwierdzić, że w Batchu można tworzyć gry komputerowe, bo https://gynvael.coldwind.pl/?id=127 :-p


edytowany 4x, ostatnio: Patryk27
Zobacz pozostały 1 komentarz
RE
dzięki stary jak byś mi nie powiedział to bym nie wiedział ;) Chodzi o sam sposób pisania w python, gdzie mi się fajnie pisze takie rzeczy mielące po opencv/ml ale gorzej to łączyć w taki bardziej "klasyczny" program na poziomie samego pythona.
PA
To tak samo można powiedzieć: "GC dotnetu jest napisane w C++, programiści C# tylko spinają wysokopoziomową logikę".
Patryk27
@part: C# jest self-hosted, zatem tak średnio; prędzej porównałbym to do moja aplikacja jest w całości napisana w C#, choć wykorzystuje bindingi do Qt, OpenCV i Tensorflow :-P
kq
Ja to bym uznał za w pełni popraawne twierdzenie ;​)
AK
  • Rejestracja:prawie 7 lat
  • Ostatnio:około 2 miesiące
  • Postów:3561
1
bilborrd napisał(a):

Niezłą dyskusję wywołałem :) widzę, że przewija się czasem twierdzenie, że są języki szybsze niż C/C++. Nie do końca rozumiem to stwierdzenie. Są to języki kompilowane do kodu maszynowego nie może być szybszych języków. Oczywiście, dużo zależy od umiejętności programisty ale teoretycznie, skoro nie mamy żadnej warstwy abstrakcji, mamy maksymalne możliwości optymalizacji i inne języki mogą być tylko równie szybkie. Może się mylę?

Chyba, że chodzi wam o to, że pewne domyślne rozwiązania jak np. polimorfizm, są lepiej zrealizowane w innych.

Np w algorytmach intensywnie alokujących (duża ilość "sztuk") Java może być szybsza *)
jest w Apache taki serwer Qpid, który ma dwie implementacje w Javie i C++. Wiem że przy C++ wisiała tak notatka "przepraszamy, ale wersja Javowa jest szybsza".

*) potoczne słowo szybkość wymaga profesjonalnych rozróżnień: throughput, maks czas reakcji, mediana, percentyl i wiele innych

hauleth napisał(a):

Czasami ze względu na konstrukcję języków może się okazać, że niektóre rzeczy kompilator może założyć, że są spełnione.

Ważne stwierdzenie.

na uK miałem przygodę (Atmega 8 to dość małe gówienko).
Po podniesieniu wersji IDE (do AS 7 już fanie robiącej C++) przeportowałem C do C++. Kompilator wyoptymalizował pola prywatne, o których miał wiedzę, ze nie są używane.
Właśnie na tej zasadzie: więcej wiedział.


Bo C to najlepszy język, każdy uczeń ci to powie
edytowany 1x, ostatnio: cerrato
Zobacz pozostałe 5 komentarzy
Wibowit
ZTCP to Rust miał jemalloc w standardzie kiedyś, a potem mieli odejść od niego na rzecz standardowego alokatora. Argumentowali to tak, że jemalloc mocno rozdmuchuje rozmiar binarki, a daje niewiele w zamian w typowych programach. Nie wiem jak to się potoczyło, bo długo nie grzebię w Ruście.
Wibowit
Java ma benchmarki typu SPECjbb, gdzie jest dużo alokacji pamięci i na nich testuje się różne implementacje GC. Czy w C++ sytuacja jest podobna? Wydaje mi się, że te benchmarki z niestandardowych alokatorów to są równie wydumane i uproszczone co te z benchmark games.
KR
Cała zabawa polega na tym, że w C++ można pisać kod niemal nigdy niczego nie alokując na stercie.
Wibowit
W HFT Java podobno alokują pule raz na starcie, a potem używają tylko tych pul obiektów. Co kto lubi.
KR
Tak, tak można, tylko taki kod jest paskudny w utrzymaniu.
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4709
1
bilborrd napisał(a):

Niezłą dyskusję wywołałem :) widzę, że przewija się czasem twierdzenie, że są języki szybsze niż C/C++. Nie do końca rozumiem to stwierdzenie. Są to języki kompilowane do kodu maszynowego nie może być szybszych języków. Oczywiście, dużo zależy od umiejętności programisty ale teoretycznie, skoro nie mamy żadnej warstwy abstrakcji, mamy maksymalne możliwości optymalizacji i inne języki mogą być tylko równie szybkie. Może się mylę?

Mnósto języków jest kompilowane do kodu maszynowego, ale taka java dopiero w trakcie działania programu, przez co kompilator np. w jvm ma dużo więcej wiedzy (statystyki) o tym jak program działa. Dodatkowo dość jasno określone zasady działania maszyny powodują, że nie ma praktycznie UB - kompilator może sobie pozwolić na dużo większe żonglowanie kodem niż w C/C++. Klasyka: już 20 lat temu jvm potrafił inlinować metody wirtualne (czyli absurd z punktu widzenia c++). Czy np. semafory (synchronized) - jeśli tylko jeden wątek coś lockuje to jvm wycina kod lock/free.

To, że przez te 20 lat jvm totalnie nie zdeklasował C/C++ w szybkości programów nawet mnie zadziwia, ale są konkretne powody (np. never ending story projektu valhalla). Taki jvm ma ciągle duży potencjał na optymalizacje, gdzie C raczej daleko nie zajdzie (C++ może ma większe szanse - jeśli nałożyć pewne ograniczenia na kod).
Natomiast jvmy i inne vm pewnie będą zawsze obsysały w zużyciu pamięci - duża część z optymalizacji wymaga przechowywania dodatkowych danych i ta ilość raczej rośnie ciągle.


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

To jest ładna teoria. Szkoda tylko, że moje 10+ lat doświadczenia z optymalizacja kodu w Javie tego nie potwierdza. JVM ma nieco więcej informacji o wykonaniu kodu ale ta informacja jest średnio użyteczna i w praktyce zysk jest mizerny - zwykle kilka %.
Przy kompilacji natywnej też można zresztą zrobić PGO. Zwykle daje od -5% do +10% wydajności, dlatego mało kto się w to bawi.

Podejrzewam, że wynika to głównie z postępu w rozwoju procesorów. Obecnie CPU sam w sobie jest taką małą maszyną wirtualną i sam robi mnóstwo "optymalizacji". Np. kompilatory nie muszą dawać hintów do przewidywania skoków, bo CPU i tak zrobi po swojemu.

Natomiast z drugiej strony JVM ma bardzo mało czasu na optymalizację a sam język narzuca pewne rozwiązania, które trudno optymalizować - np. konieczność alokacji na stercie niemal wszystkiego, konieczność obsługi metod wirtualnych, locki na każdym obiekcie, GC itp.

edytowany 2x, ostatnio: Krolik
vpiotr
Podpieranie się tym argumentem że JVM ma mało czasu jest nie do końca usprawiedliwione. Przecież można sobie wyobrazić opcję typu "optymalizuj maksymalnie", która była by użyteczna w procesach batchowych. Widocznie taka opcja niewiele by dała skoro większość opcji wspominanych przy temacie optymalizacji dotyczy pamięci.
KR
Optymalizacja całości kodu mogłaby zająć minuty a nawet godziny. Jak odpalę LTO się niewielkiego programu to już mam kilkanaście sekund na samo linkowanie. Nie możesz przegiąć z optymalizacja, bo więcej czasu stracisz na optymalizację niż na pracę aplikacji. A czas uruchamiania na JVM jest niemal zawsze i tak za długi i irytuje. Poza tym czas to nie jedyne ograniczenie. Drugim jest pamięć.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
1

Sztuczki z JVMa jak na razie przede wszystkim pomagają zbić narzut wysokopoziomowego kodu oraz koszt obsługi leniwego i dynamicznego ładowania kodu. Dynamiczne ładowanie kodu prowadzi do https://en.wikipedia.org/wiki/Open-world_assumption a więc trzeba się zabezpieczyć przed zmianą sytuacji - np klasy są ładowane w trakcie wykonywania kodu, a więc nie można na pałę założyć, że inline'ujemy wszystko bez dodatkowej ifologii na wypadek załadowania nowego kodu. Kompilacja AOT odbywa się pod https://en.wikipedia.org/wiki/Closed-world_assumption a więc łatwiej jest optymalizować - wiadomo dokładnie co w danym miejscu może się stać i nie trzeba się dodatkowo zabezpieczać.

Sporym hamulcem dla rozwoju JVMa jest to, że ten standardowy wciąż jest napisany w C++. Mamy więc sytuację kompilatorów AOT do C++ napisanych w C++ vs kompilatora JIT do Javy napisanego w C++. Wysokowydajny JIT jest raczej trudniejszy do osiągnięcia niż wysokowydajny AOT, więc trzymanie się C++a raczej nie przyspieszy postępu. Z drugiej strony w Javie implementuje się pomysły szybciej niż w C++ie. Dopiero GraalVM czyli kompilator JIT + AOT do Javy napisany w Javie zmienia sytuację. Autorzy Javy przerzucili się z zaawansowanymi eksperymentami na GraalVMa i mamy już jakieś owoce tych eksperymentów:

Kod wygenerowany przez JITa z JVMa wcale nie musi być dokładnie tak szybki jak ten wygenerowany przez kompilatory C++. Wystarczy, że będzie blisko (np spowolnienie nie większe niż 20%) i już kurczowe trzymanie się C++a stracie sens, bo te 20% wydajności będzie można odzyskać z nawiązką inwestując w wielowątkowe przetwarzanie danych.


"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 3x, ostatnio: Wibowit
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około godziny
  • Postów:2964
1

W praktyce cały czas nie jest 20% a 2x-3x i to jak się jest bardzo ostrożnym. Jak się nie uważa, i pisze w stylu OOP albo FP a nie data-oriented, to spokojnie można stracić 90% wydajności i nawet trudno zauważyć kiedy i gdzie zniknęło.

Druga sprawa to przewidywalność wydajności - w aplikacjach desktopowych ważne jest szybkie działanie od początku, a nie stopniowe rozpędzanie się. Ba! To jest ważne również w aplikacjach serwerowych. Jak klient ma zrestartować klaster ze 100 serwerów i każdy startuje 30-50 sekund, ale rozpędza się kolejne kilka minut, to trudno się dziwić, że taki klient będzie się przed tym bronić jak tylko może.

Trzecia sprawa to pamięć. Zdarza się, że JVM nawet faktycznie zbliza się do optymalnej wydajności, ale kosztem zużycia o rząd wielkości więcej RAMu. A czasem dwa rzędy wielkości. Zwłaszcza jeśli dołożymy konieczność minimalizacji pauz z GC. GC lubi dodatkowa przestrzeń.

Co do wielowątkowości - to C++ też umie w te klocki, a Rust Javę mocno przewyższa.

edytowany 4x, ostatnio: Krolik
TurkucPodjadek
TurkucPodjadek
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 4 lata
  • Postów:607
1
Krolik napisał(a):

W praktyce cały czas nie jest 20% a 2x-3x i to jak się jest bardzo ostrożnym. Jak się nie uważa, i pisze w stylu OOP albo FP a nie data-oriented, to spokojnie można stracić 90% wydajności i nawet trudno zauważyć kiedy i gdzie zniknęło.

Ale o czym mówimy? Liczby bez kontekstu nic nie znaczą, można sobie podać zupełnie dowolne dane i dowolnie je zinterpretować pod dowolną tezę - nikt nie sprawdzi. Można napisać program w Pythonie, który będzie nieskończenie szybszy niż program C, choć będą robić dokładnie to samo. Więc te dane, bez kodu i usecase są nic nie warte - możemy dyskutować jak filozofowie.

Dlaczego o tym wspominam: bo też śledze temat wydajności, i jeszcze nie trafiło mi się, żeby ktoś nie zareagował na "ostateczny" przykład wydajności w jakimkolwiek języku - zawsze znajdzie się maher co "zejdzie" kolejne kilka procent, jakimś abstrakcyjnym kodem, choć "reszta" maherów już myślała, że nie da się (dotyczy w zasadzie każdego języka).

Dobry przykład: stockfish (silnik szachowy, bardzo mocno cpu-bound), napisany w C++, gdzie nieraz PRy ciągną 20 plików masakrycznych zmian, bo ktoś "wynalazł" wzrost wydajności o 2% stosując jakieś supertricki bitowe i przesunięcia na rejestrach, ledwie udokumentowane w najnowszych CPU, które zna marny procent inżynierów. Tylko co z tego, jak np. inny silnik (LC0) jest z ~3000x wolniejszy w analizie pozycji, a gra lepiej, bo bazuje na zupełnie innym algorytmie - równie dobrze mogliby go w Pythonie napisać, bo to algorytm decyduje o tym co w tym najważniejsze: o sile gry. I podejrzewam, że podobnie jest w przypadkach optymalizacji w innych dziedzinach. Więc nie rozpędzałbym się z tą wydajnością za wczasu.

Druga sprawa to przewidywalność wydajności - w aplikacjach desktopowych ważne jest szybkie działanie od początku, a nie stopniowe rozpędzanie się.

Moim zdaniem, znowu zbyt szeroko powiedziane - jest pełno aplikacji w pythonie (to chyba nie jest przedstawiciel "szybkich" języków?) na linuksach, które mają przyzwoitą wydajność, nawet nie idzie w ogóle dociec, że one są w Pythonie (patrz: terminator, kupfer - te które ja znam). Nie robią cudów na procesorze, wystarczy, że robią co powinny i nie zauważam, by wydajnościowo odbiegały od natywnych. Jest wręcz odwrotnie, choć to wrażenie czysto subiektywne nic nie mające wspólnego z porządnymi pomiarami (krunner vs kupfer, krunner w C++, jakkolwiek go nie skonfiguruję, to zawsze jest wolniejszy niż kupfer w pythonie, więc nie wiem co on tam robi "jeszcze")

Ba! To jest ważne również w aplikacjach serwerowych. Jak klient ma zrestartować klaster ze 100 serwerów i każdy startuje 30-50 sekund, ale rozpędza się
kolejne kilka minut, to trudno się dziwić, że taki klient będzie się przed tym bronić jak tylko może.

Dziś są takie wynalazki jak canary deployment i nikt nie będzie wstrzymywał oddechu, bo jakiś restart się dzieje. Nie te czasy. Teraz część infrastruktury może się cały dzień restartować i nikt tego nie zauważy zwyczajnie (jeśli jest to zrobione dobrze)

Silv
@TurkucPodjadek: Napisałeś: "Więc te dane, bez kodu i usecase są nic nie warte - możemy dyskutować jak filozofowie". Czy uważasz, że dyskutowanie "jak filozofowie" jest czymś nieodpowiednim w tej dyskusji?
TurkucPodjadek
TurkucPodjadek
@Silv: zobacz na jakim forum sie udzielasz. Jak na mój gust, to chyba nie jest forum polityczne, religijne czy filozoficzne, tylko forum, gdzie większość piszących, to zazwyczaj inżynierowie. A inżynierowie operują na konkretnych danych, tyle, że same dane, bez właściwego kontekstu, zupełnie nic nie znaczą.
kq
Tej, ale Lc0 też jeste w C++ napisana.
TurkucPodjadek
TurkucPodjadek
@kq: tak, ale "przeszukuje" zupełnie inaczej pozycje niż stockfish, w tej samej jednostce czasu "sprawdza" kilka tysi razy mniej (średnio) i jest to zupełnie wystarczające do tego, aby grała lepiej.
Silv
@TurkucPodjadek: rozumiem.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
3

@Krolik:
Spokojnie, Java się rozwija i powoli nadrabia zaległości w wydajności.

Zacznijmy od:

Trzecia sprawa to pamięć. Zdarza się, że JVM nawet faktycznie zbliza się do optymalnej wydajności, ale kosztem zużycia o rząd wielkości więcej RAMu. A czasem dwa rzędy wielkości. Zwłaszcza jeśli dołożymy konieczność minimalizacji pauz z GC. GC lubi dodatkowa przestrzeń.

Rzeczywiście - tracing GC wymaga dodatkowej przestrzeni i to z założenia. Pojedynczy przebieg tracing GC jest kosztowny, więc w takim przebiegu musi być wyłapane wystarczająco dużo śmiecia by był opłacalny. A dużo śmiecia wymaga dużego zapasu pamięci. To nie jest wada Javy, a tracing GC, więc każdy kto używa tracing GC będzie musiał się z tym pogodzić.

Wracając jednak do wydajności alokacji skopiuję komentarze:

Alokacja w Javie nie jest wcale szybsza od malloc. Dla małych obiektów jest taka sama, dla dużych jest powolniejsza. Natywne alokatory nie stały w miejscu przez ostatnie 10 lat. - Krolik dziś, 11:50
Benchmarki mówią co innego: https://benchmarksgame-team.pages.debian.net/benchmarksgame/performance/binarytrees.html Najszybszym rozwiązaniem na mallocu (czyli bez pul obiektów) w C++ jest C++ g++ #2 zabierające 38s, dla C gcc #5 zabierające 18s, Rust ma tylko pule (typed_arena), dla Javy mamy Java #7 zabierające 8.25s, a dla C# jest C# .NET Core #6 zabierające 5.59s. Dla dużych obiektów oczywiście malloc będzie szybsze niż alokacja w Javie, bo malloc nie inicjalizuje alokowanych obiektów, a Java je zawsze zeruje (pomijając Unsafe). - Wibowit 29 minut temu

Wracając do postu:

Druga sprawa to przewidywalność wydajności - w aplikacjach desktopowych ważne jest szybkie działanie od początku, a nie stopniowe rozpędzanie się. Ba! To jest ważne również w aplikacjach serwerowych. Jak klient ma zrestartować klaster ze 100 serwerów i każdy startuje 30-50 sekund, ale rozpędza się kolejne kilka minut, to trudno się dziwić, że taki klient będzie się przed tym bronić jak tylko może.

Rozwiązania są dwa, oba oparte o GraalVMa. Jedno to native-image z GraalVMa, który kompiluje aplikację całkowicie w trybie AOT i działa to całkiem dobrze: https://quarkus.io/#container-first Drugie to jaotc czyli połączenie AOTa z JITem (przy użyciu opcji --compile-for-tiered): https://openjdk.java.net/jeps/295 i wtedy mamy zarówno szybki start dzięki binarce jak i możliwości JITa.

W praktyce cały czas nie jest 20% a 2x-3x i to jak się jest bardzo ostrożnym. Jak się nie uważa, i pisze w stylu OOP albo FP a nie data-oriented, to spokojnie można stracić 90% wydajności i nawet trudno zauważyć kiedy i gdzie zniknęło.

Tutaj też coś się dzieje, ale trzeba poczekać. Project Valhalla http://openjdk.java.net/projects/valhalla/ dla typów wartościowych i generykach na nich oraz Project Panama http://openjdk.java.net/projects/panama/ który dostarcza np API do bezpiecznego niskopoziomowego zarządzania pamięcią spoza sterty Javowej czy SIMDów. Project Panama daje takie same możliwości aranżacji struktur danych w pamięci jak typowe języki niezarządzane typu C, C++, Rust, etc

Co do wielowątkowości - to C++ też umie w te klocki, a Rust Javę mocno przewyższa.

A Golang jest jeszcze wyżej. Project Loom http://openjdk.java.net/projects/loom/ ma dostarczyć równie lekkie i szybkie abstrakcje dla wielowątkowości co te dostępne w Go. Poza tym cały czas jestem zdania, że podejście funkcyjne znacząco ułatwia pisanie programów wielowątkowych - po prostu pakuję jakiś kawałek kodu do Future'a, Task'a, Executora czy czego tam jeszcze (obojętne nawet) i nie przejmuję się data races czy tym który wątek ma zwalniać pamięć.

Poza tym, jak wspomniał @TurkucPodjadek ważna jest architektura projektu, a nie tylko niskopoziomowe optymalizacje. Do tego trzeba dodać szybkość reakcji na zmiany. Jeśli robimy projekt, który trzeba w kółko orać bo zmieniają się wymagania (to jest normą w biznesowych aplikacjach) to kluczowym parametrem jest podatność kodu na refaktoryzację. Jeśli jest niska (tzn refaktor jest pracochłonny) to będzie tendencja ku nawarstwianiu się prowizorycznych haków (często kosztem wydajności) niż przeprojektowaniu kawałka systemu, by efektywniej realizował nowe wymagania.


"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.
several
  • Rejestracja:prawie 16 lat
  • Ostatnio:4 minuty
0

Spokojnie, Java się rozwija i powoli nadrabia zaległości w wydajności.

@Wibowit jak długo już nadrabia? Nie czas żeby w końcu przeskoczyć? Zawodowo nie pracuję długo, od 2011, ale 9 lat to i tak sporo czekania i rok w rok ta sama śpiewka. Tymczasem przykład takiej ScyllaDB vs Cassandra pokazuje, że możemy jeszcze trochę poczekać. Z C++ jest wiele rzeczy nie tak, ale przynajmniej jednej rzeczy udało się w nim nie skopać, nie zabrano w nim kontroli.

EDIT:
Funny part is - java już teraz rywalizuje z C++ jeśli chodzi o performance, przynajmniej jeśli chodzi o low latency gdzie nie używa się FPGA. Tym nie mniej poza tą częścią branży, C++ nadal jest szybszy. Może javowa społeczność skupia się nie na tych aspektach, których powinna skoro wciąż czytam o nadrabianiu zaległości?


edytowany 3x, ostatnio: several
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
5

Z C++ jest wiele rzeczy nie tak, ale przynajmniej jednej rzeczy udało się w nim nie skopać, nie zabrano w nim kontroli.

W Javie też udało się pewnej ważnej rzeczy nie skopać: w dużej mierze nie ma https://en.wikipedia.org/wiki/Memory_corruption , nie ma undefined behaviour czy implementation defined (no chyba, że ktoś odpala z Javy natywny kod np poprzez JNI albo używa sun.misc.Unsafe ale tego żaden przeciętny Javowiec nie robi). Java jest na tyle przewidywalna, że każdy się może bawić w optymalizacje kodu i nie dostanie segfaultów czy wyjścia poza zakres tablic tylko exceptiona, którego można złapać i zdebugować jak każdego innego.

@Wibowit jak długo już nadrabia? Nie czas żeby w końcu przeskoczyć? Zawodowo nie pracuję długo, od 2011, ale 9 lat to i tak sporo czekania i rok w rok ta sama śpiewka.

No i jeszcze z parę lat minie zanim te projekty, o których napisałem wejdą do Javki z głównego nurtu.

Może javowa społeczność skupia się nie na tych aspektach, których powinna skoro wciąż czytam o nadrabianiu zaległości?

Autorzy Javy skupiają się przede wszystkim na tym co jest najbardziej potrzebne w typowych zastosowaniach Javy. Przeciętny Javowiec klepie kod biznesowy, a nie żyłuje stałą w złożoności obliczeniowej, więc jak na razie skupiano się na wydajności GC, modularności by umożliwić odchudzenie JRE (to był spory dług techniczny i zabrał wiele lat) czy zbijaniu narzutu wysokopoziomowego kodu.

Ponadto autorzy Java podnoszą sobie poprzeczkę i starają się wprowadzać mechanizmy bezpieczne i kompatybilne wstecznie. Dla przykładu:

  • Project Valhalla - tutaj dba się o kompatybilność wsteczną, czyli takie wprowadzenie typów wartościowych by stare kolekcje i inne klasy mogły na tym skorzystać. Ponadto typy wartościowe w Project Valhalla są immutable, więc dochodzi konieczność zaimplementowania wielu nowych optymalizacji, by wydajność była taka jak przy mutable.
  • Project Panama - tutaj dba się o https://en.wikipedia.org/wiki/Memory_safety i przewidywalny kontrakt. Nieudana zabawa ze wskaźnikami czy SIMDami ma skutkować zwykłymi exceptionami, a nie segfaultami, undefined behaviour, nadpisaniem pamięci spoza bufora przypisanego do wskaźnika itp itd Dodatkowo API do SIMDów jak i do żonglowania bajtami (padding w strukturach danych, endianess, itp) ma być przenośne między architekturami procesorów. Dzięki temu niedzielny programista będzie mógł się tym zająć bez obaw że urwie mu nogę i będzie musiał tygodniami szukać buga. Szukanie błędy będzie odbywać się tak jak w przypadku normalnych Javowych programów.
  • Project Loom - tutaj problemem jest pożenienie nowych rodzajów wątków z obecnym API czy obecnych GC z nowym sposobem obsługi stosu. Obecnie na zarządzanej stercie są tylko obiekty o regularnej strukturze (zdefiniowanej przez klasę obiektu), natomiast ramki stosu mają strukturę wyjątkowo nieregularną (zmieniającą się nie tylko z metody na metodę ale także z powodu optymalizacji, np escape analysis prowadzącej do przenoszenia alokacji ze sterty na stos). Project Loom jest o tyle istotny, że pozwala uniknąć (podobnie jak Golang) rozdwojenia kolorów funkcji (szczegóły: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ ), a więc nie trzeba każdej blokującej metody przerabiać na wersję async, bo Project Loom przerobi ją automatycznie wedle bieżących potrzeb (zamieniając operacje typu Thread.sleep na przełączenie zadania na inne, przez co nie blokujemy wątku i nie musimy ich dużo tworzyć - zaleta dokładnie taka sama jak przy typowym async).

Moje przewidywania co do popularności tych zmian są takie:

  • Project Valhalla (typy wartościowe i generyki na nich) - to będzie szeroko używane, zwłaszcza jeśli wypali plan przerobienia części już istniejących klas na klasy wartościowe (wtedy będą szeroko używane z automatu). C#-owcy stracą koronny dowód na wyższość C# czyli wyłączność na możliwość zrobienia List<int>.
  • Project Panama (konkretnie chodzi mi o niskopoziomowe, ale bezpieczne zabawy ze wskaźnikami i SIMDem) - to będzie ogólnie rzadko używane (bo w 90%+ aplikacji ważniejsze jest szybkie prototypowanie i refaktoryzacja niż żyłowanie stałych w złożoności obliczeniowej), ale będzie królować w niszach takich jak benchmarki, low-latency Java (HFT i takie tam) czy biblioteki do ciężkich obliczeń matematycznych (typu mnożenie macierzy, sztuczne sieci neuronowe, przetwarzanie obrazu, itd).
  • Project Loom (zmiana sposobu współbieżności) - tutaj migracja prawdopodobnie trochę potrwa. Trudno powiedzieć, bo nie znam innej popularnej platformy, która migrowałaby się ze zwykłych wątków na mechanizmy spotykane w Go.

Oczywiście można mieć pretensje do tego podejścia i stwierdzić, że można zrobić to prościej, np:

  • Project Valhalla - można zrobić typy wartościowe i generyki na nich niekompatybilne ze starymi mechanizmami. Wtedy zdecydowanie byłoby prościej, bo tworzyłoby się nowy system typów od nowa i od razu byłoby coś widać. Jednak problemem jest kompatybilność wsteczna. C# 2.0 mógł sobie pozwolić na generyczne kolekcje niekompatybilne ze starymi, bo C# był jeszcze młody, a kodu w nim mało. Dzisiaj C# dba o kompatybilność wsteczną prawie, że równie mocno co Java.
  • Project Panama - można by zrobić zabawy ze wskaźnikami czy SIMDy, które są nieprzenośne (osobne intrinsics dla każdej architektury procesora), unsafe i mają pełno UB czy implementation specific i wtedy rzeczywiście byłoby znacznie prościej dla autorów Javy. Jednak wtedy byłoby to równie nieprzystępne dla programisty Javy co analogiczne rozwiązania w innych językach.
  • Project Loom - można by olać continuations, fibery, itp itd mechanizmy znane np z Go i pójść drogą innych języków głównego nurtu wstawiając nową składnię dla asynca i zrzucając na programistów problem integracji kodu synchronicznego z asynchronicznym.

Co kto lubi. Java ma być językiem, który ma przetrwać kolejne dekady w korporacjach i aplikacjach biznesowych, więc musi być przystępna dla przeciętnego programisty i nadająca się do płynnej migracji starego kodu do nowych konstrukcji składniowych czy nowego API. Do tego ma być nadal bezpieczna (memory safety itd), ustandaryzowana i przenośna (ten sam kawałek kodu ma działać na różnych systemach operacyjnych i architekturach procesorów). Gdyby to nie było ważne to do Javy już dawno można byłoby napchać mnóstwo nieprzenośnych konstrukcji unsafe i chwalić się wydajnością na poziomie 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 godziny
  • Postów:2964
3

Zdaje sobie sprawę z tego, że Java nie stoi w miejscu i że te projekty usprawnią wydajność. Tylko że w tym czasie twórcy takiego GCC czy LLVM też nie próżnują.

Przykład, który podałem wcześniej dotyczył realnego kodu wziętego z istniejącego systemu. Kod był zoptymalizowany przez eksperta zajmującego się tuningiem Javy zawodowo (obecnie pracującego dla Apple) - zero alokacji na stercie, brak obiektowości, brak dynamizmu, wszędzie typy proste. Ogólnie czyta się ten kod jak C napisane w Javie. Mimo tego ostateczny rezultat jest nadal 5x powolniejszy od kodu Rust napisanego przez nooba (mnie) w trzy weekendy.

Co więcej, cała ta magia JVM wprowadza masę dodatkowej złożoności, która jakby żyje swoim własnym życiem. Ja nie wątpię, że w końcu da się osiągnąć dobrą wydajność. Możliwe, że przy kolejnej iteracji nasz ekspert poprawiłby kod jeszcze bardziej i przyspieszył go o te brakujące 5x. Jednak nie ma mowy o jakiejś większej produktywności Javy w tym przypadku. Kod powstaje znacznie wolniej, jest znacznie mniej czytelny i bardzo łatwo go zepsuć.

Przy każdym wydaniu naszego softu w Javie trafi się zawsze ileś testów wydajnościowych, które pokazują na regresję wydajności. Tak samo raz na 100 klientów trafi się jakiś, któremu automagiczne GC świruje. Albo taki, który ma 10 sekundowe pauzy. Oczywiście domyślam się, że to jest niezależne od języka i w C++ byłyby regresje. Jednak nie trzeba by było walczyć z taką ilością magii w samym środowisku wykonawczym.

Zobacz sobie ile jest opcji samego GC i ile jest osób w środowisku, które rozumieją co te opcje robią. Spróbuj też wrzucić jakiś nietrywialny kod na profiler Javy i sprawdź czy wyniki mają sens i ile czasu musisz mierzyć aby sygnał zaczął przewyższać szum. Tworzenie wydajnego kodu w Java to jest zabawa w chodzenie po polu minowym.

W C, C++, Rust jak mam regresję, to w ostateczności podejrzę kod w assembly i zweryfikuję czy kompilator nie porobił głupot. W Javie mogę oczywiście też podejrzeć, ale nic mi to nie da bo u klienta może być zupełnie inaczej!

zawsze znajdzie się maher co "zejdzie" kolejne kilka procent, jakimś abstrakcyjnym kodem, choć "reszta" maherów już myślała, że nie da się (dotyczy w zasadzie każdego języka).

Pytanie jakim kosztem. Jeżeli trzeba zrezygnować z 90% udogodnień języka, aby uzyskać dobrą wydajność, to nie możemy wtedy używać argumentu, że Java / C# / Python / (inny wysokopoziomowy wynalazek) oferują większą produktywność niż języki od początku zorientowane na wydajność.

Różnice w produktywności programistów pomiędzy językami są często przeszacowane. Np. to badanie stwierdza, że jest pewna różnica między C++ a Java, ale jest dość niewielka:

https://www.academia.edu/26018067/Comparison_of_software_development_productivity_based_on_object-oriented_programming_languages

edytowany 2x, ostatnio: Krolik
Zobacz pozostałe 7 komentarzy
KR
" Skoro ma heapdump 50 GB to pewnie nie słyszał o mikroserwisach" - szukanie błędu w jednym porytym programie jest łatwiejsze niż szukanie błędu w systemie rozproszonym składającym się z N porytych programów :P
Wibowit
Tu się nie zgodzę. Przejście na architekturę mikroserwisów wymusza do pewnego stopnia luźne powiązania, bo nikomu nie chce się utrzymywać rozbuchanego API. W przypadku monolitu współdzielenie kosmicznie rozbudowanych API jest proste, bo nie trzeba pisać żadnych RESTów, DTOsów, mappingów, itp itd
jarekr000000
Skoro ma heapdump 50 GB to pewnie nie słyszał o mikroserwisach a co ma RAM do mikroserwisów? można mieć prosty serwis key value / cache i tyle zająć. Jak się nie da odtworzyć na sprzęcie to znaczy, że sprzęt nieprzygotowany do akcji - po prawdzie ze zrzutami 50 gb jest większy problem z transportem niż samą analizą.
KR
Problem jest taki, że np. MAT nie umie wczytać takiego heap-dumpa bez alokowania tyle samo RAMu co heap dump zajmuje. Sprzęt nieprzygotowany - ale ok, co polecasz? Dawać programistom maszynki po 128 GB RAMu? Ale wiesz, wtedy znajdzie się nagle klient, który ma heap ustawiony na 200 GB i problem tyko się przesunął dalej.
jarekr000000
Dawać RAM to jedno. Nie wiem czy prosty jhat sobie nie radzi lepiej (ale dawno nie miałem problemu - mam 128 GB....). Problem jest taki, że znalezienie maszyny to nie problem, problem że przez różne security i reguły prawne często tego zrzutu nie da się wynieść z sieci klienta, a tam zwykle wszystkie maszyny to jakiś skansen. Więc już miałemn przypadki, że heap miał 3 GB i mógłbym odtworzyć na telefonie... ale klient nie ma takiego komputera (w odpowiedniej podsieci) (a nawet jego admini- serio :-)).
TurkucPodjadek
TurkucPodjadek
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 4 lata
  • Postów:607
0
Krolik napisał(a):

Różnice w produktywności programistów pomiędzy językami są często przeszacowane. Np. to badanie stwierdza, że jest pewna różnica między C++ a Java, ale jest dość niewielka:

https://www.academia.edu/26018067/Comparison_of_software_development_productivity_based_on_object-oriented_programming_languages

Zerknąłem w to badanie, jest z roku 2010 (i odwołuje się w źródłach do prac z lat 80 nawet)... 2010... nie wiem czy to te czasy, gdy w Javie gettery i settery trzeba było nawet do hello world stosować :-), co w połączeniu z badaniem, w którym jednym z wiodących wskaźników jest ilość linii kodu, wiadomo do jakiego wniosku to poprowadzi. Rusta, Go (self compiled dopiero od 1.5 - 2015) czy Kotlina wtedy jeszcze nie było, więc nie wiem czemu dla porównania nie użyto np. Pythona wtedy.

Bardziej do mnie przemawia to "badanie": https://thume.ca/2019/04/29/comparing-compilers-in-rust-haskell-c-and-python/#python - przykład w Python tutaj rzekomo był "przeładowany" for fun i z nudów już, a i tak był w kwestii linii kodu 2x mniejszy niż baseline, co pokazuje, że kod w języku statycznie typowanym i nastawionym na poprawnośc i wydajność, możesz po napisaniu równie dobrze wyrzucić do kosza, bo ze względu na time-to-market, konkurencja będzie mieć już z 3 lub 4 wersję swojego produktu, co prawda pełną błędów, ale będzie go mieć i klienci będą już korzystać, gdy Ty dopiero skończysz swoją "poprawną" 1.0. I to zakładając, że nie wystrzeli Cię z siodełka wcześniej brak ważnych bibliotek - np. Rust i Go ze względu na "młodość" są na to bardzo narażone, a nie każdy od razu zakłada, że idzie w mikroserwisy i brak takich bibliotek nadrobi jakimś serwisem we właściwym języku, który się odpyta po jakimś grpc czy kolejkami.

Zobacz pozostałe 9 komentarzy
Wibowit
Ile % programistów używa wprost WinAPI do obsługi IO?
KR
Nie chodzi o to aby używać wprost, ale aby warstwa abstrakcji która jest nad API systemu nie ograniczała możliwości i nie wprowadzała bezsensownych narzutów. "Nie dowieszv się czy plik to named-pipe na Linuksie, bo Windows tego nie ma" - taka filozofia jest bez sensu. Większość programistów nie używa API systemu wprost, ale dobrze mieć taką możliwość na tę jedną okazję na 100.
KR
Abstrahując już od API sam język oparty o GC komplikuje używanie I/O. Gdzie i kiedy zamknąć zasób to w Javie/C# problem co najmniej tego samego kalibru co gdzie wstawić free w C. W obu przypadkach jak zapomnisz to będziesz mieć crash... po kilku dniach.
Wibowit
Owszem są takie problemy, ale zwykle jest tak, że pliki są wczytywane w całości naraz, a połączenia są tak czy siak zamykane po timeoutach jeśli się ich wprost nie zamknie, więc to zarządzanie zasobami jest proste. Problemy mieliśmy z plikami, w sensie brak zamykania plików skutkował przekroczeniem ilości otwartych plików, ale i tak tego typu błędy występują u nas rzadko. Named pipe to nigdy w kodzie komercyjnym nie widziałem. Częściej były problemy z wyciekami pamięci lub jej przekroczeniem, co względnie łatwo debuguje się analizując heap-dumpy.
TurkucPodjadek
TurkucPodjadek
Python ma context managera co robi to automatycznie - żadna ingerencja w kod nie jest wymagana, a np. Go ma defer, które "dodaje" się zaraz pod open w 95% przypadków, a to języki z GC. Jeśli to jest "komplikowanie", to chcę zobaczyć "uproszczenie" w C/C++, bo chyba argument jest odwrócony (zakładam, że przypadkowo)
PA
  • Rejestracja:ponad 6 lat
  • Ostatnio:około 2 lata
  • Postów:426
0
Krolik napisał(a):

Różnice w produktywności programistów pomiędzy językami są często przeszacowane. Np. to badanie stwierdza, że jest pewna różnica między C++ a Java, ale jest dość niewielka:

https://www.academia.edu/26018067/Comparison_of_software_development_productivity_based_on_object-oriented_programming_languages

Zerknąłem w badanie i nie wydaje mi się wiarygodne. Zadania są w stylu "Matrix addition integrated by real numbers", " Computing the linear regression equation parameters", "Both storing and searching records from a file". Przy tak prostych zadaniach rzeczywiście java nie będzie bardziej produktywna niż cpp. Ba kod w javie nawet nie będzie się jakoś mega różnił od cpp.

EDIT: to jest imo bardziej wiarygodne - https://www.ifpug.org/wp-content/uploads/2017/04/IYSM.-Thirty-years-of-IFPUG.-Software-Economics-and-Function-Point-Metrics-Capers-Jones.pdf
EDIT2: trzeba jeszcze zauważyć, że badania zazwyczaj sprawdzają, ile zajmuje Ci wyklepania zadania od 0. Sam maven daje +10 do produktywności javy. Nie mówiąc o wszystkich javowych bibliotekach, które działają bez zabawy - w cpp, jeżeli uda Ci się pobrać projekt z gh i make się nie wywali, to resztę dnia świętujesz.

edytowany 2x, ostatnio: part
KR
No, ale to już porównujemy biblioteki a nie języki. Zgadzam się, że za produktywność odpowiadają biblioteki. Jak trzeba napisać coś z AI/ML albo numerycznego w Javie to lepiej dać sobie spokój.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
1

Przykład, który podałem wcześniej dotyczył realnego kodu wziętego z istniejącego systemu. Kod był zoptymalizowany przez eksperta zajmującego się tuningiem Javy zawodowo (obecnie pracującego dla Apple) - zero alokacji na stercie, brak obiektowości, brak dynamizmu, wszędzie typy proste. Ogólnie czyta się ten kod jak C napisane w Javie. Mimo tego ostateczny rezultat jest nadal 5x powolniejszy od kodu Rust napisanego przez nooba (mnie) w trzy weekendy.

Co więcej, cała ta magia JVM wprowadza masę dodatkowej złożoności, która jakby żyje swoim własnym życiem. Ja nie wątpię, że w końcu da się osiągnąć dobrą wydajność. Możliwe, że przy kolejnej iteracji nasz ekspert poprawiłby kod jeszcze bardziej i przyspieszył go o te brakujące 5x. Jednak nie ma mowy o jakiejś większej produktywności Javy w tym przypadku. Kod powstaje znacznie wolniej, jest znacznie mniej czytelny i bardzo łatwo go zepsuć.

Skoro Java jeszcze nie ma konstrukcji językowych, ani API do niskopoziomowych optymalizacji to nie dziwne, że takie zabawy są w Javie mało opłacalne. To trochę jakby powiedzieć, że w Pythonie żonglowanie bajtami by uzyskać wydajność zbliżoną do C++a jest niepraktyczne i dlatego ten język nie sprzyja produktywności. Java na razie jest nastawiona głównie na aplikacje biznesowe, gdzie jest dużo warstw abstrakcji, dużo mielenia stringów, dużo używania standardowych kolekcji, dużo niskiej jakości (ale i tak poprawnie działającej) wielowątkowości, 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.
edytowany 1x, ostatnio: Wibowit
Zobacz pozostałe 36 komentarzy
KR
Wycieki zasobów / pamięci w Javie też można osiągnąć na wiele sposobów. Znacznie więcej niż w Rust. To co podlinkowałeś opisuje jak celowo zrobić wyciek.
jarekr000000
Gdyby w C++ standardem było przekazywanie przez wartość (ew. const referencje) to by był całkiem fajny język (pomijając fakt, że wskaźnik jest oczywiście przekazywany przez wartość, ale nie o to chodzi). Ale każda moja krótka przygoda z C++ (dawno temu miałem dłuższą), pokazuje że ludzie jeszcze nie doszli do tego (strzelam, ze dzięki uczelniom promującym raka: C z klasami).
KR
A z tym się w pełni zgadzam.
AK
@jarekr000000: C z klasami to był miód, przynajmniej gościa dało się ciągnąć w górę. Teraz uczą C ze strumieniami
AK
Liczne modele pamięci C++ to problem
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około godziny
  • Postów:2964
3

No i teraz wracamy do głównego tematu - na desktopie i w aplikacjach mobilnych wydajności brakuje. Procesory nie przyspieszają już tak jak kiedyś, a aplikacje są coraz bardziej rozbudowane.

Efekty? Współczesne interfejsy lagują bardziej niż Windows na 486 20+ lat temu. W VSCode wpisywanie literek potrafi lagować!

Zapotrzebowanie na szybki kod będzie rosło, bo sprzęt już tak nie przyspiesza jak kiedyś i wydajność będzie coraz bardziej ograniczała funkcjonalność.

Przy tym sam desktop może nawet będzie tracił na znaczeniu, ale za to aplikacje mobilne będą zyskiwać na znaczeniu. A tak liczy się niskie zużycie baterii. W tym zakresie języki pozwalające tworzyć lekkie i szybkie aplikacje będą nadal w użyciu. Np. Google Fuchsia stawia na C++, Rust I Dart.

edytowany 1x, ostatnio: Krolik
AK
Wiesz, czy program JavaScriptowy to taki prawdziwy desktop ... czy taki web zamknięty w "boxie". Dla mnie ovedesign/błąd koncepcyjny, i są tego konsekwencje
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
1

Efekty? Współczesne interfejsy lagują bardziej niż Windows na 486 20+ lat temu. W VSCode wpisywanie literek potrafi lagować!

Mi kilkanaście lat temu strony bez JSa i obrazków potwornie lagowały (widać było proces rysowania strony poszczególnymi etapami) na Internet Explorerze na kompie z chyba Celeonem 300 MHz i 96 MiB RAMu.
VSCode zamula, ale pomiędzy JSem, a C++em jest sporo innych platform do wyboru, a w takim IntelliJu edycja kodu przebiega bardzo płynnie.


"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.
AK
  • Rejestracja:prawie 7 lat
  • Ostatnio:około 2 miesiące
  • Postów:3561
1
Krolik napisał(a):

No i teraz wracamy do głównego tematu - na desktopie i w aplikacjach mobilnych wydajności brakuje. Procesory nie przyspieszają już tak jak kiedyś, a aplikacje są coraz bardziej rozbudowane.

Efekty? Współczesne interfejsy lagują bardziej niż Windows na 486 20+ lat temu.

To może problem tych "interfejsów" (na marginesie, wolałbym jakbyś użył "interfejsu użytkownika"). Rzekomo chcianych przez użytkowników, "projektowanych" przez marketingowców. nawiasem, właśnie minute temu się zmagałem z aplikacją webową od firmy finansowej, która miała "ułatwiacz", fruwający przycisk "skopiuj do schowka", który znikał po najechaniu, ale zaraz potem zasłaniał pole.

Czy branża UI zmądrzeje?

Zapotrzebowanie na szybki kod będzie rosło, bo sprzęt już tak nie przyspiesza jak kiedyś i wydajność będzie coraz bardziej ograniczała funkcjonalność.

Wątek skręcił z "desktop". Nie neguję, że szybki kod ogólnie w algorytmach to OK, nie ma gadania. Ale po co hyper super duper szybki kod w UI, jeśli większość jest interpretowana dla zwiększenia bajerów?
Przykład WPF versus WinForms, JavaFX versus Swing, to samo w C/C++


Bo C to najlepszy język, każdy uczeń ci to powie
edytowany 1x, ostatnio: AnyKtokolwiek
somedev
  • Rejestracja:prawie 7 lat
  • Ostatnio:prawie 5 lat
  • Postów:666
0
AnyKtokolwiek napisał(a):

Wątek skręcił z "desktop". Nie neguję, że szybki kod ogólnie w algorytmach to OK, nie ma gadania. Ale po co hyper super duper szybki kod w UI, jeśli większość jest interpretowana dla zwiększenia bajerów?
Przykład WPF versus WinForms, JavaFX versus Swing, to samo w C/C++

O co chodzi z tym WPF vs WinForms?

AK
Ze więcej bajerów, XML do interpretowania itd, skiny, pierdoły ...
somedev
  • Rejestracja:prawie 7 lat
  • Ostatnio:prawie 5 lat
  • Postów:666
0

WPF różni się w podstawie od WinForms, tym, że posiada swój silnik renderujący i stos okien, a WinForms używa WinAPI. To są zupełnie inne technologie... Niemniej WPF na współczesnych komputerach wcale nie jest taki wolny, a co do samego UI - od lat nie pisze się aplikacji zależnych od prędkości UI a raczej idzie się w asynchroniczność. Zresztą to nie UI może spowalniać. UI zazwyczaj jest proste, natomiast operacje na danych mogą w miarę rozrostu danych być bardziej czasochłonne. Z doświadczenia wiem, że przy rozwoju programu czas potrzebny na dana operacje jest zależny od długości przetwarzania a nie czasu wyrysowania okna.

AK
No właśnie, szybkość GUI nie jest wiodąca.
somedev
No tak, ale to też zależy gdzie ;) Jeśli licze kostkę olapową to to, czy menu otworzy mi się w 1s czy w 0.2s nie ma znaczenia. Natomiast aplikacje gdzie robi się dużo prostych rzeczy to już jest ważne. Np. wystawianie pozycji zamówienia operując jedynie klawiaturą. Operatorki potrafią wystawiać pozycje w mniej niż 1s mając dostatecznie szybki interface. Znane sa tez przymułki aplikacji "moern" jak Google Hangouts, Discord, PGAdmin4, etc. Nie zdarzało się tak w czasach kontrolek WinApi i uważam, to za najlepszy interface.
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około godziny
  • Postów:2964
0

Interfejs nie musi być szybki w sensie "przepustowości" (throughout) ale ma mieć niskie opóźnienia (response time). I dlatego mimo tego że to powiedzmy taka Java z Hotspotem potrafi osiągnąć niezłą wydajność w hurcie, to do desktopa nadaje się słabo i praktycznie na desktopie umarła (poza jednym lub może dwoma IDE).

Na Androidzie też koncepcja maszyny wirtualnej umarła dość dawno temu i teraz jest ART (czyli AOT), a w Fuchsji Google położył jeszcze większy nacisk na kod natywny i tam chyba wszystko musi być skompilowane normalnie statycznie.

edytowany 1x, ostatnio: Krolik
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
1

Skoro AOT na Androidzie niby uratował Javę, to czemu miałby nie uratować na desktopie? native-image z GraalVM CE jest za darmo.


"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 godziny
  • Postów:2964
0

Fajnie, tylko po co? I jak to niby zlikwiduje problemy np. z lagami GC? To rozwiązuje tylko problem ładowania / kompilacji w tle.
Poza tym Java jest masakrycznie trudna do dobrej kompilacji statycznej, bo polega na dynamicznych wywołaniach, więc po co mieć wady wydajnościowe Javy i wady dystrybucji natywnych binarek? Lepiej już wziąć coś co było projektowane z myślą o natywnych obrazach od początku.

TurkucPodjadek
TurkucPodjadek
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 4 lata
  • Postów:607
2

@Krolik: nie rozumiem esencji Twojego problemu - może go jakoś opisz, przedstaw kod, cokolwiek. Na razie, opisujesz abstrakcyjno-teoretyczne problemy czegoś tam bez żadnego konkretnego use case na stole. Faworyzujesz ogólnikowo jedną rzecz (wydajność), kosztem wszystkiego innego (przynajmniej ja to tak rozumiem). Na przykładzie silników szachowych obecnych pokazałem Ci, że to błędne podejście (jako ogólne). Nie wiem, przedstaw konkretny problem, opisz swoje pomiary i pokaż coś, co udowadnia w "praniu" Twoje twierdzenia, pokazuje Twój problem - np. masz kod w Javie, który z powodu tego, że to Java/JVM, ma taki a taki problem, a problem rozwiązujesz takim prostym kodem C++ czy Rust[1], który tego problemu nie ma. Bo na razie to dyskusja religijna, niby górnolotne kwestie latają, ale konkretów zupełnie brak.

[1] Risky as hell - niemal zawsze, na odpowiednio specjalistycznym forum pokażą Ci, że języka programowania tak naprawdę jeszcze nie znasz (albo nie wiesz jaki masz problem - to jeszcze gorzej). Polecam to podejście osobom, które chcą się czegoś nauczyć. :-) Zresztą, polecam moje 2 ostatnie wpisy na mikroblogu o Rust - zawsze mnie to zaskakuje ile można się dowiedziec z komentarzy pod takim wpisem, a jak tylko proste biedakody pokazuję.

Wibowit
Risky as hell ale nie tak ryzykowny jak Java vs C# :p
FE
Przecież pokazywał konkretny use-case procesowania jakiś tam plików w Javie vs Rust.
Wibowit
No i do tego mamy try-with-resources i co teraz?
FE
No nic bo to nie jest ten przykład. Try-with-resources nie wpływa na wydajność.
Wibowit
No i tyle warte są te przykłady.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
1

Kompilacji za pomocą native-image nie trzeba wymyślać od nowa za każdym razem. Powstają narzędzia, które to automatyzują i upraszczają.

Czy GC dużo zmienia? Moim zdaniem niespecjalnie. Programy z MS Office są napisane w C++, a potrafią się zamrozić na wiele sekund i to regularnie (głównie Excel i Outlook w moim przypadków). Głupie notatniki też się zamrażają przy otwieraniu dużych plików. Komunikatory są pisane często w JS lub Javie i korpo chętnie z nich korzystają. W sumie to na firmowym lapku niestandardowe (tzn nie systemowe, nie przeglądarki i nie z MS Office) apki pisane w C/ C++ to nawet mniejszość - tylko notatniki i terminale. Komunikatory (przez bałagan w firmie mam ich kilka) i narzędzia to głównie JS i Java.

Sytuacje w których GC odczuwalnie przeszkadza w aplikacjach desktopowych to moim zdaniem raczej rzadkość. Większym problemem jest brak asynchroniczności. GUI się totalnie przycina, bo w tle coś się mieli, albo coś czeka na komplet nowych danych.


"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 godziny
  • Postów:2964
2

Polemizuję z tezą z pierwszego posta:

Projektów w których szczególnie zależy klientowi na wydajności jest już mało i wraz z rozwojem sprzętu będzie coraz mniej.

  1. Dynamiczny rozwój sprzętu to już przeszłość. O 2-krotnym wzroście wydajności na półtora roku można zapomnieć. Dobijamy do granic fizycznych możliwości. Będzie co najwyżej więcej rdzeni, ale też bez szału, bo chłodzenie / zużycie energii nie pozwoli. Na urządzeniach mobilnych liczy się zużycie baterii.

  2. W każdym projekcie wydajność jest istotna, jedynie w innym miejscu leży granica pomiędzy nieakceptowalną a akceptowalną wydajnością. Czasami sama zmiana wydajności otwiera nowe możliwości funkcjonalne. Gdybyśmy nadal internet mieli na modemach 28 kbps to taki serwis jak YouTube nigdy nie miałby racji bytu.

  3. Większość oprogramowania, które używam ma wydajność na granicy akceptowalności lub niestety poniżej. Ale mało kto faktycznie tym się przejmuje, ponieważ mylnie uważa się że czas programisty jest droższy od czasu maszyny. VSCode porzuciłem i używam tylko jak muszę, bo lagi mnie irytują. Irytuje mnie jak na przeglądarkę muszę czekać 2 sekundy aż się otworzy. Oczekiwania klientów wobec wydajności będą rosły.

  4. Wielu adwersarzy tej dyskusji robi tu mylnie ciche założenie, że dobra wydajność jest ZAMIAST czegoś innego i że coś tam innego WYKLUCZA. Np. że można mieć wydajniejszy kod ale kosztem produktywności albo kosztem stabilności itp. To jest bardzo naciągane założenie. C++ ma faktycznie słabo zrobione sprawy związane z bibliotekami i zależnościami, co może ubić produktywność, ale to tylko tooling i nie ma nic wspólnego z tym, czy programy w C++ są wydajne czy nie. To wynika po prostu z historii. Rust jakoś ma o niebo lepiej rozwiązaną modularyzację niż Java/C# i nic to w wydajności mu nie przeszkadza.

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).
Nawet Java na IntStreamach, które rzekomo są zoptymalizowane będzie jakieś 5x powolniejsza. Po co oddawać wydajność za nic w zamian?

edytowany 7x, ostatnio: Krolik
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
1

Dynamiczny rozwój sprzętu to już przeszłość. O 2-krotnym wzroście wydajności na półtora roku można zapomnieć. Dobijamy do granic fizycznych możliwości. Będzie co najwyżej więcej rdzeni, ale też bez szału, bo chłodzenie / zużycie energii nie pozwoli.

AMD pokazuje, że da się upakować 2x więcej rdzeni przy tym samym TDP co Intel, a to dzięki postępowi w TSMC. Jeszcze dobre kilka lat będziemy mieć zwiększanie ilości rdzeni. A skoro ilość rdzeni się zwiększa to coraz ważniejsze jest łatwe programowanie wielowątkowe. Javowym rozwiązaniem na to ma być Project Loom https://openjdk.java.net/projects/loom/ Do wielowątkowości jest wiele podejść, każdy niech sobie oceni w czym mu się najwygodniej kodzi.

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).

Ten drugi jest wolniejszy, bo tam są Integery, a nie inty (czyli jest boxing). Na razie nie ma reified generics, więc takie benchmarki testuję dwa zupełnie inne przypadki. Gdybyś testował na tablicach to miałoby to więcej sensu.


"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 3x, ostatnio: Wibowit
Zobacz pozostałe 4 komentarze
Wibowit
Żeby jeszcze Intel nie był dziurawy :] Wydajność powinna być ważniejsza niż budowa procesora. Zresztą Intel też idzie powoli w cziplety (np Lakefield), ale to szczegół.
KR
AMD też jest dziurawy. Nie żeby to było dobrze, czy coś. Stwierdzam tylko fakt.
Wibowit
AMD Zen 2 ma IPC pomiędzy Intel Skylake (14nm), a Intel Ice Lake (10nm), podobnie z taktami. Tyle, że Ice Lake kończy się na 4 rdzeniach, a Zen 2 na 64 rdzeniach.
KR
Spoko, jakbym teraz miał kupować, to pewnie kupiłbym AMD. Fajnie że jest konkurencja.
loza_wykletych
loza_wykletych
Trudno nie mieć dziurawego procesora w architekturze RISC która udaje CISC a dodatkowo hostuje cały niezależny od wszystkiego system operacyjny który dowolnie może wpływać na egzekucję danego kawałka kodu. A mówili że Transmeta Crusoe to szaleństwo :D
KR
Moderator
  • Rejestracja:około 21 lat
  • Ostatnio:około godziny
  • Postów:2964
0

A skoro ilość rdzeni się zwiększa to coraz ważniejsze jest łatwe programowanie wielowątkowe. Javowym rozwiązaniem na to ma być Project Loom https://openjdk.java.net/projects/loom/

Za późno i za mało. W jaki sposób Loom pozwoli pisać łatwiej kod współbieżny?
Dla mnie to rozwiązuje bardzo specyficzny problem pisania kodu asynchronicznego tak jakby był synchroniczny. Ok, tylko że to nie jest wcale łatwiejsze niż to co jest teraz. A i inne języki już to dawno mają (Go, Rust, Kotlin).

AK
No tak, ale nieco przenosisz płaszczyznę dyskusji. Jak Kotlin, to już nie opór przeciwko JVM
KR
Jest Kotlin native :P
Wibowit
Kotlin native nie ma GC?
KamilAdam
@Krolik: dlaczego Kotlin Native jest dobry a Java Native zła?
KR
To był tylko przykład na zapóźnienie Javy.
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:12 minut
1

Dla mnie to rozwiązuje bardzo specyficzny problem pisania kodu asynchronicznego tak jakby był synchroniczny.

No to bardzo podobnie do składni async/await, z tym, że nie trzeba w ogóle stosować async/await i dzięki temu unikamy duplikowania metod. Nie trzeba mieć osobnych metod async i nie-async, bo to czy są async zależy od tego na jakim typie wątku/ executora/ etc go puścisz, a nie jaką ma sygnaturę.


"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
Super, ale nadal możesz zrobić data-race, a to jest największa bolączka programowania współbieżnego.
Wibowit
Masz jakąś konkretną sytuację na myśli? Kto czyta jeden zasób systemowy z wielu wątków?
KR
Mam tak dużo takich sytuacji w historii, że już przestałem notować. Jeden zasób z kilku wątków bardzo łatwo niechcący użyć. Wystarczy, że ktoś nie zdaje sobie sprawy, że jakaś ścieżka jest wykonywana z wielu wątków i umieści wywołanie w złym miejscu. Java nie daje kompletnie ani kontroli ani żadnej widoczności co jest jedno- a co wielo-wątkowe. Miliśmy nawet kiedyś realny data-corruption w bazie spowodowany tym, że kod początkowo zaprojektowany jako thread-unsafe po niezależnej zmianie w innym module znalazł się w kontekście wielowątkowym.
Wibowit
A ja nie mam takich sytuacji w ogóle. Kto pracuje w typowych apkach Javowych/ Scalowych/ etc? :)
Wibowit
Poza tym ZTCP to autorzy Rusta zastanawiali się nad takim podejściem jak w Golangu czy Project Loom, ale odpuścili ze względu na integrację z bibliotekami natywnymi spoza Rusta. Większy priorytet miała kompatybilność z istniejącym natywnym kodem niż unikanie zaśmiecania kodu wszędobylskimi asyncami.
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Koszalin
  • Postów:10094
0

Zawsze znajdą się ludzie którzy będą chcieli wycisnąć max'a z hardwareu. nawet jak gry będą w rozdzielczości 256k na 288MHz i wymagały 1024 GB RAMU, to będą ludzie którzy będą chcieli je odpalić na Ultra High, zamiast High.

Zobacz pozostałe 3 komentarze
KR
Analogia słaba. Gdyby to było 10% wydajności to pewnie by się jakoś trzymała. Ty rozumiem zjadasz 1/5 tego co zamówiłeś?
plx211
4k = 3840 × 2160; 256k = 4k * 64 = (3840 × 2160) * 64 = 245760 × 138240 = 33973862400; załóżmy 32bity na pixel 33973862400 * 32 = 1087163596800 = 126.56 Gigabytes. Mało tego ramu :)
Riddle
@Krolik: Są ludzie którzy chcą 100% ze sprzętu, są ludzie którzy nie kładą nacisku na performance; i nie ma to nic wspólnego z żarciem na talerzu. Koniec gadki.
vpiotr
256 kolorow na 2xx MHz to juz bylo (jakies 20 lat temu) :-)
Maciej Cąderek
Maciej Cąderek
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Warszawa
  • Postów:1264
4

Atwood's Law:

Any application that can be written in JavaScript, will eventually be written in JavaScript

BraVolt
because most people don't need anything else

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.