czwartek, października 22, 2009

C# i Java okazały się szybsza od Pythona :-) [było Java okazała się szybsza od C# i Pythona]

[update: 15/01/2010 - okazało się, że pomiary dla C# były źle przeprowadzane co zaniżało jego wydajność mniej więcej o 10 razy!!!! Błędnie użyłem DateTime.Now.Ticks zakładając, że zwraca ilość naonsekund, a zwraca ilość ticków, których w nanosekundzie mieści się dziesięć. Niestety nikt tego wcześniej nie zauważył i złe wyniki poszły w świat. [tytuł posta też zmieniony ;-)]]
Nowe wyniki prezentują się tak [wyniki dla procesora Intel Core 2 Duo T6600 2.20 GHz [2 rdzenie 64 bitowe pod 64 bitowym Windows 7]:
C# z .NET 4.0 - 1.17 ms
Java 1.5 z przełącznikiem -server - 1.096 ms
Java 1.6 z przełącznikiem -server - 2.8895 ms
Python 2.6 - 10.88 ms
Z radością jednak odnotowuję, że słuszne były moje przewidywania i słuszne zdziwienie słabym wynikiem C# :-) szkoda tylko, że wszystkiemu winien był taki błąd :-)

[update: 23/10/2009 - dodałem informacje o wynikach programu w C i parę uwag]


Tak nie miałem pomysłu na to co dziś napisać ;-) więc zrobiłem sobie szybki test co jest szybsze [w obliczeniach] Java, Python czy C#, kontrolnie postanowiłem dodać też C :-).
Przyznam, że z języków wykonywanych w wirtualnych maszynach stawiałem na C#.

W każdym z języków napisałem program, którego celem było policzenie numerycznie 1000 razy całki oznaczonej w przedziale od -10 do 10 [niedomkniętym z prawej] w 10000 krokach z funkcji:
f(x)=e-x2

Wynikiem jest coś bliskiego pierwiastkowi z liczby pi [swoją drogą to była rzecz na analizie matematycznej która mnie zachwyciła, całka z funkcji w której użyta jest e, a wynikiem jest pierwiastek z pi, czyli istnieje związek między niektórymi stałymi matematycznymi... może to zrobiło na mnie takie wrażenie bo byłem wtedy świeżo po czytaniu Kontaktu Carla Sagana? :-)].

No i wyniki wyglądają tak [wszystkie czasy dla pojedynczego policzenia całki]:

.


Język/ProcesorAMD Turion64 ML-30*Intel Core Duo 2.16 GHzCeleron 900 MHz [Asus EEE]

.


Cb/d4 ms4 ms

.


Java18 ms10 ms10 ms

.


C# [wyniki powinny zostać prawdopodobnie podzielone przez 10 z racji błędu w programie testowym]45 ms32 ms34 ms

.


Python60-74 ms**27 ms30.5 ms

Przyznam, że byłem zaskoczony. Przed uruchomieniem testów dałbym sobie rękę obciąć za to, że z języków wykonywanych przez maszyny wirtulane wygra C#, bo coś mi się po głowie kołatało, że .NET swobodnie korzysta z koprocesora [kto jeszcze pamięta co to jest? ;-) ja pamiętam, że moją przygodę z PC zaczynałem na komputerze bez koprocesora i że były nawet softwareowe emulatory tegoż :-)], czego Java nie może robić bo jej matematyka zmiennoprzecinkowa nie jest do końca zgodna z tą stosowaną w x86 [dla pewności w przypadku Java'y uruchomiłem jeszcze test z arytmetyką zgodną ze strictfp, i wtedy czas jednej iteracji to 20 ms dla Turiona 64].
A tu proszę, Java okazała się w tym przypadku 2.5-3 raza szybsza od C# :-) i 2.85 do 3.33 razy szybsza od Pythona [testy z Pythonem 3000, czy może 3.1? pokazują, że Python troszkę przyśpieszył].

Do testów użyłem Sun Java 1.6.0_15 [czyli chyba najnowszej], dla Pythona był to ActiveState Python 2.5 i oryginalny Python 2.5 z Python.org, w przypadku .NET użyłem wersji 3.5 z włączoną optymalizacją.

Programy wyglądały tak [umieszczam tylko funkcje obliczające całkę, N=10000, kody źródłowe i wersje skompilowane znajdziecie w archiwum, chętnie poznam Wasze wyniki :-)].

Java:
static double calc() {
double sum = 0;
for (int i=0; i<N; i++) {
double x = 20.0*i/N-10.0;
sum+=Math.pow(Math.E, -x*x)*(20.0/N);
}
return sum;
}

C#:
static double calc() {
double sum = 0;
for (int i = 0; i < N; i++) {
double x = 20.0f * i / N - 10.0f;
sum += Math.Pow(Math.E, -x * x) * (20.0 / N);
}
return sum;
}

Python:
def calc():
sum=0
for i in range(0,N):
x=20.0*i/N-10
sum=sum+math.e**(-x**2)*(20.0/N)
return sum

C:
double calc() {
int i;
double sum = 0;
for(i=0; i<N; i++) {
double x = 20.0*i/N-10.0;
sum+=pow(M_E, -x*x)*(20.0/N);
}
return sum;
}


Przyznam, że jestem pozytywnie zaskoczony wynikiem Java'y :-)
Jest co prawda wolniejsza od C, ale "tylko" o 2.5 raza, w przypadku C vs. C# mamy różnicę prawie 1 rzędu w wydajności, a to już coś.

Wszystkie testy odbywały się na moim laptopie, z procesorem Turion 64ML-30 1.6 GHz ściętym do 800 MHz.

Jak komuś się będzie chciało to prosiłbym o Wasze wyniki :-)



* Turion 64ML-30 o nominalnym taktowaniu do 1.6 GHz, ale softwareowo "obcięty" do 800 Mhz
** ActivePython wydaje się być wolniejszy od "oryginalnego" Pythona.



Podobne postybeta
Raspberry Pi to nie jest demon prędkości ;-)
Całkujący Dart ;-)
Plus dla Scala, minus dla Groovy ;-)
Język Go dla Windows :-)
A JavaScript i tak szybszy ;-)

38 komentarzy:

  1. Uruchomiłem moje testy na moim firmowym laptopie [Intel Core Duo 2.16 GHz] i wyniki są jeszcze ciekawesze :-)
    Java - 10 ms
    Python - 27 ms
    C# - 32 ms

    Java 1.6.0_16, .NET 3.5 i róźnica jest chyba w Pythonie, bo to nie ActiveState a to co można ściągnąć ze strony pythona.

    OdpowiedzUsuń
  2. Dla porównania na firmowym laptopie, kod w C potrzebuje 4 ms na obliczenie całki :-) Czyli Java nie jest taka wolna :-)

    OdpowiedzUsuń
  3. Mysle ze dla calosci formy warto by bylo przetestowac tez szbkosc C.

    OdpowiedzUsuń
  4. Zrobiłem to ;-) o czym piszę wyżej ;-)
    C - 4 ms
    Java - 10 ms
    Python - 27 ms
    C# - 32 ms
    Na Core Duo 2.16 GHz

    OdpowiedzUsuń
  5. Mała podpowiedź. JVM jeżeli widzi taką pętle to szybciutko kompiluje sobie bytecode do kodu natywnego. Dla mojego testu w pierwszych 10 obrotach czasy wykonania calc() wynosiły:
    32,26,9,9,9,8,8,9,8,9
    W ostatnich 10:
    4,4,5,4,4,5,4,4,5
    A zatem tyle ile w C. Ameryki tutaj raczej nie odkrywam, ale od kilku lat JVM z tym małymmykiem kompilacji do kodu natywnego w locie dla często wykorzystywanych fragmentów jest chyba najfajniejszym środowiskiem do pisania kodu wydajnego i jednocześnie eleganciego oraz łatwego w utrzymani nawet przez mniej doświadczonego programistę.

    OdpowiedzUsuń
  6. @koziołek wiem :-) dlatego właśnie całka była liczona 1000 razy, po to by wynik się ustabilizował. Było to krzywdzące dla C, który praktycznie od początku jest w stanie "polecieć" pełną prędkością, a faworyzowało Java i C# [Pythona nie, bo Python sam się przyznaje, że w jego przypadku optymalizacja to proste wyrżnięcie __doc__], które mogą dokonać kompilacji w locie, a nawet optymalizacji kodu przez obserwowanie co robi pętla. Ale ciekawe było popatrzeć jak wyglądają różnice w wynikach, mnie zaskoczył .NET, bo choć go nie lubię to wydawało mi się, że powinien mieć wyniki podobne do Java'y.

    OdpowiedzUsuń
  7. W kodzie pythonowym masz obliczanie kwadratu przez x**2, za to w innych źródłach x*x. U mnie wersja z x**2 wykonuje się w 18-18.5ms, za to wersja z x*x w 15.5-16ms. Uruchamiałem na Pythonie 2.6.2 dla win32, z python.org. Trochę się dziwię, że python sam tego nie zauważa i najprawdopodobniej liczy to przez pow(x, 2.) co jest dosyć wolne - może nie mam włączonej jakiejś optymalizacji?

    Trochę się zdziwiłem, że jak zmieniłem range na xrange to czas był taki sam (w granicy błędu).

    Szczerze mówiąc właśnie wynik Pythona najbardziej mnie zaskoczył (pozytywnie). Tam nawet wykonanie pustych pętli zajmuje wieki - szkoda, bo ze wszystkich tych języków ten jest moim ulubionym. Ale w końcu python nie jest od obliczeń numerycznych - można, ale prędzej przez numpy.

    Javą bardzo pozytywnie zaskoczyłem się już nie raz - mam porównanie, bo piszę sporo ciężkich obliczeniowo rzeczy w C i podobne rzeczy w Javie. Chociaż samego języka nie lubię to jestem przekonany, że jego powolność to głównie nieprzyjemne wrażenie pozostałe w głowach użytkowników z czasów kiedy była naprawdę wolna i jak w 1999 roku na Pentiumie z 64MB ramu wchodziło się na stronę z appletem javy to lampka od dysku zaczynała migać jak do disco, wszystkie procesy się zamrażały i spokojnie można było iść na kawę...

    OdpowiedzUsuń
  8. Zrobiłem małe porównanie na moim sprzęcie, pod systemem Linux
    Maszynka służy wyłącznie jako przeglądarka, więc procesor stłumiony jeszcze bardziej niż Twój.

    $ cat /proc/cpuinfo
    model name : Intel(R) Pentium(R) M processor 1500MHz
    cpu MHz : 598.498
    cache size : 1024 KB

    Podaję wyniki z polecenia time, które jest nieco bardziej wiarygodne.
    Ze względu na system podarowałem sobie .net ale porównanie C i Java mówi samo za siebie.

    time speed
    7,96s user 0,04s system 95% cpu 8,350 total
    time java -server Speed
    11,80s user 0,13s system 91% cpu 13,041 total
    time python speed.py
    58,66s user 0,48s system 87% cpu 1:07,68 total

    OdpowiedzUsuń
  9. @blog dlaczego uważasz, że time jest bardziej wiarygodne? Przecież ono mierzy czas działania programu, a nie to było istotą pomiarów.
    Wiadomo, że uruchomienie programu zabiera czas, ale w przypadku złożonych problemów obliczeniowych ten czas jest pomijalny.

    a ja pokusiłem się o zrobienie części testów na moim nowym laptopie ;-)
    I tak jedna iteracja zajęła:
    C 32bit [kompilator z Dev-Cpp] - 0.168 ms
    C 64bit [lcc-win32 64bit] - 0.68 ms
    Java 32bit - 4.7 ms
    Java 64bit - 3.8 ms
    .NET 64bit - 14 ms
    Python 2.5.2 32bit - 10.3 ms
    Python 2.5.4 64bit - 10.16

    OdpowiedzUsuń
  10. Aż świerzbi mnie napisanie tego w php, by pokazać dzieciom neo co jest wydajniejsze :D

    Hm... Scala/Ruby(JRuby)/Groovy no i jeszcze jak wygląda sprawa z Jthonem. Wiele tzw. postmodernistycznych języków programowania można ruszyć na JVM nie. Ciekawe mogą być różnice na poziomie samej maszyny.

    OdpowiedzUsuń
  11. @RMK
    polecenie time jest bardziej wiarygodne, ponieważ współczesne systemy są wielozadaniowe i czas procesora jest dzielony z innymi programami, które mogą "niespodziewanie" zacząć pożerać zasoby, fałszując w ten sposób wyniki. Oto przykład:

    speed 7,28s user 0,06s system 57% cpu 12,847 total
    speed 7,24s user 0,03s system 96% cpu 7,512 total

    w pierwszym przypadku miałem uruchomione dwa procesy.

    Oczywiście taki sposób pomiaru jest krzywdzący dla języków mających duży narzut przy starcie, ale przy większej ilości iteracji ta różnica będzie się coraz bardziej zacierała, podczas gdy błędy wynikające z "szumów tła" nasilały by się coraz bardziej.


    @koziołek,
    co do wyników PHP to chyba nie ma wątpliwości, skoro kompilacja na JVM oznacza zazwyczaj 6x przyśpieszenie.
    Nie wiem jak z Jthonem, ale JRuby jest wyraźnie szybszy niż CRuby 1.8. Nie porównywałem z Ruby 1.9 - tu różnica będzie mniejsza.

    OdpowiedzUsuń
  12. @koziołek natchnąłeś mnie ;-) wcześniej myślałem o użyciu JavaScript'u ale wydawało mi się to głupim pomysłem, bo przecież wolny jest........
    I takie mam wyniki [na mojej firmowej maszynie]:
    cscript [część Windows Scripting Host] - między 41 a 52 ms
    Firefox 3.5.3 - 3.782 ms
    Chrome 4.0.223.11 - 7.591 ms
    IE8 się poddał
    Opera 10.00 - 22-23 ms
    WTF? JavaScript w FF szybszy czy porównywalny do C?

    OdpowiedzUsuń
  13. Dodając do tego JavaScriptowego testu, tutaj kod:
    N=10000;
    M=1000;

    function calc() {
    var sum = 0;
    var i;
    for (i=0; i<N; i++) {
    var x = 20.0*i/N-10.0;
    sum+=Math.pow(Math.E, -x*x)*(20.0/N);
    }
    return sum;
    }

    var start = new Date().getTime() ;
    var i;
    var sum=0;
    for (i=0; i<M; i++) {
    sum+=calc();
    }
    var end = new Date().getTime();
    var time = end - start;
    document.write((time*1.0/M)+"
    ");

    Wyniki są bardzo niestabilne, bo mogą się różnić nawet o 30-40%
    Gdy chcecie spróbować w WSH, to document.write zmieńcie na WScript.Echo i nagrajcie plik jako speed.js

    OdpowiedzUsuń
  14. Są niestabilne, bo zapewne przeglądarka ciągnie też inne duperele np. pluginy, które korzystają z JS. Samo przetwarzanie JS jest jednowątkowe więc każda duperela otwarta w tle będzie zaburzać pracę.

    OdpowiedzUsuń
  15. @blog po to odpalałem te programy testowe po kilka razy. Przełączenie między wątkami i procesami kosztuje, ale mniej niż np. uruchomienie JVM.

    OdpowiedzUsuń
  16. @RMK
    Nie do końca. Czas startu JVM przy 1000 iteracjach jest mniejszy od błędów pomiaru wynikających z tego że mierzysz czas rzeczywisty zamiast czasu procesora.

    Zobacz zresztą jeszcze raz wyniki:

    $ time java -server Speed
    12
    java -server Speed 11,82s user 0,09s system 95% cpu 12,487 total

    Pierwszą liczbę wydrukował Twój program, resztę wypisał "time".

    Te liczby są baaaardzo podobne, z tym że proces wykorzystał "tylko" 95% czasu procesora - więc pomiar czasu rzeczywistego jest obarczony 5% błędem.

    Taka ciekawostka,
    pobawiłem się Waszym przykładem w JavaScript i tu wyniki są jeszcze ciekawsze. Widać jak długą drogę przebył ten język od swych narodzin :)

    Spidermonkey (silnik ze starego firefox'a)
    $ time js speed.js
    178.142
    js speed.js 174,36s user 0,87s system 98% cpu 2:58,80 total

    Rhino (implementacja java)
    $ time rhino speed.js
    55.721
    rhino speed.js 53,82s user 0,50s system 95% cpu 56,905 total

    Google V8 (wersja z przed pół roku)
    time ~/app/js-v8 speed.js
    16.732
    ~/app/js-v8 speed.js 16,47s user 0,10s system 97% cpu 16,971 total

    Niestety nie mam najnowszego silnika, który siedzi w Fx3.5 a który ma własny JIT - jego wyniki powinny znajdować się gdzieś pomiędzy Rhino a V8.

    OdpowiedzUsuń
  17. @blog U mnie okazuje się, że V8 jest wolniejszy od FF3.5.2 :-) ale możliwe, że to nie wina samego silnika, ale tego, że jest osadzony w przeglądarce, i czas zabierać może przeglądarka.

    Z tego co widzę na WinXP przy użyciu timeit [z Windows Resource Kit, który podobno jest odpowiednikiem time] to procesy "testowe" używają procesora w 96.5%, a uruchomienie JVM potrafi zająć nawet 4 sekundy ;-) czyli żeby porównywać czas ładowania JVM i przełączania wątków to programy dla JVM powinny działać ponad 114 sekund. Tak btw. w ciągu przeciętnie tych 11 sekund moja Winda przerzuca kontekst ponad 100 razy ;-) czyli ponad 10 tysięcy razy na sekundę.

    OdpowiedzUsuń
  18. @GMK,
    co do porównania z Fx3.5 to spróbuję później jeszcze coś wykombinować. Zazwyczaj v8 jest szybsze, ale w tym przypadku może być inaczej - wszystkie te nowe maszyny wirtualne są dość trudne do przewidzenia, co chwilę dodają kolejne optymalizacje kodu.

    Jeśli chodzi o naszą dyskusję na temat polecenia time, to wychodzą tu różnice pomiędzy używanymi przez nas systemami:

    U mnie start JVM to 0,2 - 0,4s
    natomiast różnice wynikające z "szumów tła" to 1,2s

    Tu masz przykład Twojego programu dla N=0

    $ time java -server Speed
    0
    java -server Speed 0,19s user 0,04s system 67% cpu 0,339 total

    Zgaduję że większość czasu pożerają operacje dyskowe.

    Przyszła mi do głowy jeszcze jedna rzecz... Zgaduję że robiąc kilka testów odrzucasz te z "nieprawidłowymi" wynikami? Jeśli tak to faworyzujesz programy z krótkim czasem wykonywania.
    Wyobraź sobie co będzie jeśli np Twój zegarek co 30s rysuje wskazówki zabierając 100% czasu procesora na 1s. Na monitorze systemowym niewiele będzie widać, bo ten uśrednia wyniki - będziesz tylko widział 3% obciążenie systemu.
    Krótki program będzie miał szczęście, ale jeśli coś działa minutę, albo dwie?

    OdpowiedzUsuń
  19. @blog Uruchamianie JVM jest tricy ;-) może zająć do 4 sekund, szczególnie gdy uruchamia się po raz pierwszy, a w innym momencie może pójść jak burza. Przed chwilą zrobiłem testy i teraz przy pierwszym uruchomieniu potrzebowała 400-500 ms, a w kolejnych już tylko 120-160 ms.

    Chodzi też o to, że niedokładność pomiaru wynikła z "szumów" jest zazwyczaj podobna dla wszystkich pomiarów, czyli błąd względny jest prawie zawsze taki sam [i dla Windows wynosi około 3.5%], fakt że jak coś się wykonuje 10 ms to ten błąd może wynieść 0.35 ms, a jak coś się wykonuje 100 ms to wyniesie 3.5 ms, ale porównanie rzędów wielkości jest nadal uzasadnione, bo 10 ms +/i 0.35 ms jest 10 razy mniejsze niż 100 ms +/- 3.5 ms.
    Doliczanie czasu potrzebnego na uruchomienie faworyzuje C i w przypadku Windows prawdopodobnie również .NET, a "krzywdzi" Java'ę i Pythona.

    A jako fizyk z wykształcenia nie mogę sobie pozwolić na nieścisłości w "procedurze" badawczej ;-)
    Każdy program jest uruchamiany 3 razy [czasem więcej] i jako wynik podawana jest średnia z tych uruchomień, wszystkie wyniki które odstają zbytnio od normy są odrzucane, odstawanie od normy znaczy co najmniej 30-40% odchyłkę, bo widać wyraźnie, że w tym czasie komputer miał ciekawsze rzeczy do robienia.
    Jest tu milczące założenie, że komputer w trakcie wszystkich uruchomień jest podobnie obciążony, co można uznać za uzasadnione przypuszczenie z racji tego, że w momencie testów robię testy dla jednego języka, później dla drugiego, trzeciego i tak dalej, a następnie odpalam znów dla wszystkich języków i sprawdzam ich wyniki [praktycznie zawsze są porównywalne z tymi wcześniejszymi].

    OK, tu testy w których wszystko wykonywało się 30 sekund :-) [wyniki są uśrednione z 3 pomiarów]
    Java - 10.25 ms
    C# - 34.14 ms
    Python - 29.19 ms
    C - 4.25 ms
    Żeby nie liczyć zbytnio czasów potrzebnych na odwołanie się do systemu w celu ustalenia czasu, działa to tak, że jest 100 iteracji, pobranie czas i sprawdzenie czy już kończyć, później czas jest dzielony przez liczbę wykonań funkcji calc().

    OdpowiedzUsuń
  20. Hej,
    Można by się pokusić o odpalenie testu dla Pythona z JITem, dla wyrówniania szans - CPython domyślnie nie używa JITa. Wystarczy zainstalować psyco umieścić na początku skryptu:
    import psyco
    psyco.full()

    OdpowiedzUsuń
  21. Coś jest na rzeczy :-)
    Z psyco i kompilacją JIT 5.83 ms, bez 13.68 ms na moim Core 2 Duo 2.2 GHz [czy jakoś tak]. Jest poprawa :-)
    Dla porównania Java 64 bit potrzebuje 4.43 ms na 1 iterację.

    OdpowiedzUsuń
  22. Hmmm... bardzo ciekawe
    Moje wyniki .Net 4.0 vs Java 1.6.0_07 na Core-i7:
    http://img515.imageshack.us/img515/9586/bnc3.png

    Jak widac, DIAMETRALNIE rozne.
    Inny prosty test:
    http://img42.imageshack.us/img42/6766/bnccs.jpg
    http://img683.imageshack.us/img683/5762/bncjv.jpg

    Tutaj Java 17(sic!) razy wolniejsza od c#4.0
    Skad te wyniki? Przyznaje, ze srednio znam sie na Javie, wiec moze robie cos nie tak?

    OdpowiedzUsuń
  23. @KomarWodny: Możesz zapodać źródła z tego drugiego testu, bo literki ciut małe i nie umiem doczytać.

    A wyniki pierwszego testu już rozumiem. Walnąłem babola w kodzie dla C# i nikt go nie zauważył [chociaż rozumiem dlaczego, bo nie widać go w treści postu a nikt niestety nie pociągnął całych źródeł], w C# używałem DateTime.Now.Ticks zakładając, że zwraca ono nanosekundy, a zwraca 1/10 nanosekudny, czyli z grubsza można by próbować dzielić wyniki wyżej przez 10 by uzyskać prawidłowe wartości, wtedy wg. powyższych wyników Java byłaby 3 razy wolniejsza.
    Chociaż w rzeczywistości jest podobnie wydajna, tutaj wyniki dla Java'y
    http://myscreen.przemelek.pl/img?id=agpzY3JlZW4ybmV0chELEgpTY3JlZW5TaG90GM5lDA
    A tu dla C#:
    http://myscreen.przemelek.pl/img?id=agpzY3JlZW4ybmV0chELEgpTY3JlZW5TaG90GLZtDA
    już po usunięciu błędu.

    Będę musiał zmienić treść posta żeby odpowiadał rzeczywistości. Dzięki za sprawdzenie.

    OdpowiedzUsuń
  24. Ja dodam od siebie (mimo, ze to dawno było), ze metoda testowa jest conajmniej zła. Żeby zbadać prawidłowo czas wykonania aplikacji (nie używaj w C# trybu deubga - skompiluj i uruchom z linii poleceń będzie działał szybciej) to jeszcze wypadałoby zadbać o to, żeby takie same i taka sama ilość procesów była uruchomiona. C# testujesz kiedy masz włączone JVM a JVM zżera więcej zasobów niż .NET framework (widać na screenach). Taka różnica przy tak niewielkich różnicach czasowych może naprawdę kolosalną róznicę zrobić

    OdpowiedzUsuń
  25. A gdy testuje JVM mam włączonego .NETa. Testowałem to też poza środowiskami i wyniki są porównywalne. Jeśli twierdzisz inaczej, to proszę o dowody, chętnie je przejrzę.
    Btw. jak na screenach widać, że JVM zżera więcej zasobów niż .NET? Chodzi o to, że więcej okien jest otwarte?
    Porównywalne wyniki były gdy odpalałem JVM i .NETa jako "jedyne" procesy [poza systemowymi i explorerem].

    OdpowiedzUsuń
  26. Ta. Teraz zauważyłem (to ten sam Anonimowy co wczoraj) niestety ale bezedurny sposób zliczenia.

    1. System.currentTimeMillis() - zwraca w milisekundach, więc ta sama jednostka powinna być użyta przy .NET ....
    2. Obliczenie milisekund w .NET milisekund tak
    Console.WriteLine(time / 1000 / M);
    jest conajmniej dziwne....
    3. Do obliczenia powinna być użyta ta konstrukcja
    Console.WriteLine(time / TimeSpan.TicksPerMillisecond / M);
    co da nam rzeczywiste wyniki.

    Z moich testów po poprawieniu wynika, że .NET jest 4 razy szybszy niż Java...

    Porównanie wychodzi

    1125 dla .NET i 4641 dla Javy. Pythona nie instalowałem bo nie mam takie potrzeby. Dla ciekawości wrzucę aplikację w nocy na jakiś mocny serwer i zobaczymy ile tam będzie działać.

    OdpowiedzUsuń
  27. z ciekawości zrobiłem to samo w PHP




    Wynik u mnie: 7.093357

    OdpowiedzUsuń
  28. @jmail:
    1) jest opisane, że w pierwszej wersji błędnie założyłem, że funkcja .NETowa zwraca nanosekundy, dlatego wyniki dla .NET zostały poprawione [czyli czas został zmniejszony o 10, co zresztą pokazały testy już z poprawionym obliczaniem]. Dodatkowo to czy mierzy się nanosekundy, milisekundy czy nawet godziny nie ma znaczenia w momencie gdy zapewni się odpowiedni interwał na pomiar. W przypadku milisekund i nanosekund gdy na cały test potrzeba 2 sekund, a w tym trakcie wykonuje się 10 mln operacji [gdy jako operację traktujemy pojedynczą iterację pętli] to zmiana jednostki pomiarowej wprowadza w najgorszym przypadku [czyli takim gdy coś trwało nie 2000 milisekund, a 1999.001 milisekundy [a zostało policzone jako 2000] różnicę wyniku na poziomie 0.5 promila, to było wałkowane wyżej w komentarzach gdy była mowa o JavaScripcie. To potwierdzają też testy przeprowadzone z użyciem System.nanoTime(). Z tego co pamiętam kod testów nie był zmieniany żeby była dokumentacja wcześniejszego błędu o którym przeczytać możesz u góry postu.
    2) masz info o błędzie, fakt jest to dziwne bo błędne
    3) była, o czym masz w updacie o której mowa w wyższych punktach.
    4) zrób test dla Java'y z przełącznikiem -server, wtedy dostaniesz takie wyniki jak moje. O czym też masz w opisie.

    Szczerze to nadal dziwią mnie wyniki Java'y zważywszy, że nie może ona używać do obliczeń kooprocesora [w pełni], a C# może. W przypadku .NET/C# jest też przyrost prędkości w .NET 4.0. W Java'ie prędkość spada po przejściu z 1.5 na 1.6 ;-)

    Ciekawy wynik dla PHP.

    OdpowiedzUsuń
  29. @jmail: jeszcze jedno, jak możesz podziel się źródłem w PHP i swoimi wersjami dla C# i Java'y. Bo ewidentnie widzę, ze trzeba będzie jeszcze raz to opisać [bo nie wszyscy czytają update].

    OdpowiedzUsuń
  30. Ten komentarz został usunięty przez autora.

    OdpowiedzUsuń
  31. Kod PHP:

    $N = 10000;

    $M = 1000;
    $E = 2.71828182845904523536;

    function calc() {
    global $N;
    global $E;

    $sum = 0;
    for ($i=0; $i<$N; $i++) {
    $x = 20.0*$i/$N-10.0;
    $sum+=pow($E, -$x*$x)*(20.0/$N);
    }
    return $sum;
    }

    $time = microtime(true);
    $s = 0;
    for ($i=0; $i<$M; $i++) {

    $s+=calc();

    }
    $time2 = microtime(true)-$time;
    $time = $time2/$M;
    printf("%.3f\r\n", $time);

    Wyniki:
    PHP: 0.034s
    Mono: 0.017s
    Python: 0.010s
    Java: 0.003s
    PHP+HipHop: 0.003s

    Z czego ostatni wynik nie świadczy o szybkości PHP tylko C++. HipHop for PHP działa na takiej zasadzie że przetłumacza kod PHP na C++, a następnie go kompiluje. Link do projektu: http://developers.facebook.com/hiphop-php/

    P.S Sorry za podwójnego posta

    OdpowiedzUsuń
  32. Super, dzięki za kod w PHP :-)
    Ciekawe wyniki, choć może trochę trudne do odczytania, wypadałoby chyba zwiększyć ilość powtórzeń żeby wyniki były bardziej widoczne.
    Dziwne, że Mono wypadło tak słabo, ciekawe w ogóle jak Mono wypada w porównaniu do .NET na Windows.

    Słyszałem o projekcie HipHop, choć nie przepadam za PHP to bardzo podoba mi się podejście Facebooka, zamiast przepisywać na "lepsze" technologie postanowili uderzyć w słabość technologii której używali dzięki czemu uzyskali chyba lepsze wyniki i to taniej niż gdyby przenieśli wszystko na jakaś "poważną" platformę.
    "" z racji tego, że takie terminy jak "lepsza technologia" i "poważna" są dość umowne ;-)

    OdpowiedzUsuń
  33. kurde :F wklejałem źródła PHP ale je wywalił jakiś hmmmm zabezpieczacz przed wstrzyknięciem kodu ;) pewnie przez to, że znaczniki php dostałem :F

    Tutaj źródła PHP

    function getTime() {
    list($usec, $sec) = explode(' ', microtime());
    return ((float)$usec + (float)$sec);
    }

    $N = 10000;
    $M = 1000;

    function calc() {
    global $N, $M;
    $sum = 0;
    for ($i = 0; $i < $N; $i++) {
    $x = 20.0 * $i / $N - 10.0;
    $sum += exp(-1*$x * $x) * (20.0 / $N);
    }
    return $sum;
    }

    $start = getTime();
    $s = 0;
    for ($i = 0; $i < $M; $i++) {
    $s += calc();
    }
    $time = getTime();
    echo round($time - $start,6);

    co do C# jedyną zmianą jaką wprowadziłem w Twoje źródła opisałem wyżej - przeliczenie z użyciem funkcji od ticków.

    Co do Javy z przełącznikiem server u mnie wydajność skoczyła mniej więcej o dwa razy - 2324

    Moje wątpliwości zrodziły się z tego, że byłem przekonany, że mam już świeże źródła (te po poprawkach)

    lol :F

    JavaScript:

    1355 - FF 3.5.8 - szybciej niż Java oO

    Z ciekawości jeszcze Java ME zrobie :F (ciągnę moduły do Beans'ów)

    OdpowiedzUsuń
  34. To jeszcze moje wyniki dla przeglądarek:
    - Epiphany (Webkit) - 2.342
    - Chrome - 2.884
    - Firefox 3.6 - 6.487
    - Opera 10.10 - 11.811

    Operka pewnie lepiej by wypadła w najnowszej wersji 10.50, ale niestety nie mam jak tego przetestować ze względu na system (Ubuntu). Firefox też powinien mieć lepszy wynik pod Windowsem

    OdpowiedzUsuń
  35. Nie mogłem się oprzeć ;)

    program speed
    real(kind=8), parameter :: e = 2.718281828459045
    real(kind=8) :: x
    integer(kind=2), parameter :: n = 10000
    integer(kind=2) :: i, j
    real(kind=8) :: wynik, t_pocz, t_koniec, pokaz
    call cpu_time(t_pocz)
    do j= 1,1000
    sum=0.
    do i = 0,10000
    x = 20.*i/n-10.
    wynik=e**(-x*x)*(20./n)
    sum = sum + wynik
    end do
    end do
    call cpu_time(t_koniec)
    pokaz = sum
    print *,'Wynik calkowania :', pokaz
    print *,'Czas trwania [ms]:',t_koniec-t_pocz/1000
    call sleep(15)
    end

    OdpowiedzUsuń
  36. Poprawiona wersja w Fortranie 90 :)

    program speed
    !Skompilowac mozna np. tak:
    !gfortran -O3 -fomit-frame-pointer speed.f90 -o speed-fortran.exe
    !~3.02 ms i ~2.75 ms dla wersji alternatywnej
    real(kind=8), parameter :: e = 2.71828182845904524
    real(kind=8) :: x
    integer(kind=2), parameter :: n = 10000
    integer(kind=4) :: i, j
    real(kind=8) :: wynik, t_pocz, t_koniec, pokaz
    call cpu_time(t_pocz)
    do j= 1,1000
    sum=0.
    do i = 0,10000
    x = 20.*i/n-10.
    !wynik=exp(-x*x)*(20./n) wersja alternatywna
    wynik=e**(-x*x)*(20./n)
    sum = sum + wynik
    end do
    end do
    call cpu_time(t_koniec)
    pokaz = sum
    print '(A,1f22.17)','Wynik calkowania :', pokaz
    print '(A,1f14.9)','Czas trwania [ms]:',t_koniec-t_pocz
    !call sleep jest potrzebne tylko na MS systemach
    call sleep(12)
    end

    OdpowiedzUsuń
  37. Laptop Firmowy Dell Latitude D830
    Ubuntu 10.04, jądro 2.6.32-34
    CPU 0 - 2.20 GHz (Intel Core 2 Duo)
    CPU 1 - 2.20 GHz (Intel Core 2 Duo)

    Java (1.6.0_26) : 3.246 s
    Mono (v.2.4.4) : 18.903 s
    Python (2.6.5) : 10.072 s
    c : 1.635 s

    OdpowiedzUsuń
  38. c# (.net 4.0) RunTime 00:00:01.32
    java (1.6) RunTime: 3.526 s


    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Diagnostics;
    namespace speedtest
    {
    class Program
    {
    const int N = 10000;
    const int M = 1000;
    static double calc()
    {
    double sum = 0;
    for (int i = 0; i < N; i++)
    {
    double x = 20.0f * i / N - 10.0f;
    sum += Math.Pow(Math.E, -x * x) * (20.0 / N);
    }
    return sum;
    }
    static void Main(string[] args)
    {
    Stopwatch watch = new Stopwatch();
    watch.Start();
    double s = 0;
    for (int i = 0; i < M; i++)
    {
    s+=calc();
    }
    watch.Stop();
    TimeSpan ts = watch.Elapsed;

    // Format and display the TimeSpan value.
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds,
    ts.Milliseconds / 10);
    Console.WriteLine("RunTime " + elapsedTime);
    Console.ReadKey();
    }
    }
    }

    import com.google.common.base.Stopwatch;


    public class Speed {
    private static final int N=10000;
    private static final int M=1000;
    static double calc() {
    double sum = 0;
    for (int i=0; i<N; i++) {
    double x = 20.0*i/N-10.0;
    sum+=Math.pow(Math.E, -x*x)*(20.0/N);
    }
    return sum;
    }
    //public static void main(String[] args)
    public static void main(String[] args) {
    //long start = System.currentTimeMillis();
    Stopwatch stopwatch = new Stopwatch().start();
    double s=0;
    for (int i=0; i<M; i++) {
    s+=calc();
    }
    stopwatch.stop(); // optional

    long millis = stopwatch.elapsedMillis();


    System.out.println("RunTime: " + stopwatch);
    }

    }

    OdpowiedzUsuń