Wróćmy do pierwotnego wiersza: „Jak język, którego kompilator napisany jest w C, może być szybszy niż C?”
Myślę, że to naprawdę znaczyło: jak program napisany w Julii, którego rdzeń jest napisany w C, może być szybszy niż program napisany w C? W szczególności, w jaki sposób program „mandel” napisany w Julii może działać w 87% czasu wykonania równoważnego programu „mandel” napisanego w C?
Traktat Babou jest jedyną jak dotąd poprawną odpowiedzią na to pytanie. Wszystkie pozostałe odpowiedzi jak dotąd odpowiadają mniej więcej na inne pytania. Problem z tekstem Babou polega na tym, że opis teoretyczny „Co to jest kompilator” o długości wielu akapitów jest napisany w taki sposób, że oryginalny plakat prawdopodobnie będzie miał problemy ze zrozumieniem. Każdy, kto pojmie pojęcia, o których mowa w słowach „semantyczny”, „denotacyjnie”, „realizacyjny”, „obliczalny” i tak dalej, zna już odpowiedź na pytanie.
Prostszą odpowiedzią jest to, że ani kod C, ani kod Julii, nie jest bezpośrednio wykonywalny przez maszynę. Oba muszą zostać przetłumaczone, a ten proces tłumaczenia wprowadza wiele sposobów, w których wykonywalny kod maszynowy może być wolniejszy lub szybszy, ale nadal daje ten sam efekt końcowy. Zarówno C, jak i Julia wykonują kompilację, co oznacza serię tłumaczeń na inną formę. Zwykle plik tekstowy czytelny dla człowieka jest tłumaczony na jakąś wewnętrzną reprezentację, a następnie zapisywany jako sekwencja instrukcji, które komputer może bezpośrednio zrozumieć. W przypadku niektórych języków jest to coś więcej, a Julia jest jednym z nich - ma kompilator „JIT”, co oznacza, że cały proces tłumaczenia nie musi odbywać się od razu dla całego programu. Ale wynikiem końcowym dla dowolnego języka jest kod maszynowy, który nie wymaga dalszego tłumaczenia, kod, który można wysłać bezpośrednio do procesora, aby coś zrobić. W końcu TO jest „obliczenie” i istnieje więcej niż jeden sposób, aby powiedzieć procesorowi CPU, w jaki sposób uzyskać pożądaną odpowiedź.
Można sobie wyobrazić język programowania, który ma zarówno operator „plus”, jak i „zwielokrotnienie”, oraz inny język, który ma tylko „plus”. Jeśli twoje obliczenia wymagają mnożenia, jeden język będzie „wolniejszy”, ponieważ oczywiście procesor może zrobić oba bezpośrednio, ale jeśli nie masz możliwości wyrażenia potrzeby pomnożenia 5 * 5, musisz napisać „5 + 5 + 5 + 5 + 5 ”. Ta ostatnia zajmie więcej czasu, aby dojść do tej samej odpowiedzi. Przypuszczalnie coś takiego dzieje się z Julią; być może język pozwala programiście określić pożądany cel obliczenia zestawu Mandelbrota w sposób, którego nie można bezpośrednio wyrazić w C.
Procesor zastosowany w teście został wymieniony jako procesor Xeon E7-8850 2,00 GHz. Benchmark C wykorzystał kompilator gcc 4.8.2 do wygenerowania instrukcji dla tego procesora, a Julia korzysta ze struktury kompilatora LLVM. Możliwe, że backend gcc (część, która wytwarza kod maszynowy dla konkretnej architektury procesora) nie jest tak zaawansowany jak backend LLVM. To może mieć wpływ na wydajność. Dzieje się też wiele innych rzeczy - kompilator może „zoptymalizować”, być może wydając instrukcje w innej kolejności niż określona przez programistę, a nawet nie robiąc żadnych rzeczy, jeśli może przeanalizować kod i stwierdzić, że nie są wymagane, aby uzyskać właściwą odpowiedź. A programista mógł napisać część programu C w sposób, który spowalnia go, ale nie „
Wszystko to można powiedzieć: istnieje wiele sposobów pisania kodu maszynowego w celu obliczenia zestawu Mandelbrota, a używany język ma znaczący wpływ na sposób pisania tego kodu maszynowego. Im więcej rozumiesz na temat kompilacji, zestawów instrukcji, pamięci podręcznych itd., Tym lepiej będziesz przygotowany do uzyskania pożądanych rezultatów. Główną zaletą wyników testu cytowanych dla Julii jest to, że żaden język ani narzędzie nie jest najlepsze we wszystkim. W rzeczywistości najlepszym współczynnikiem prędkości na całym wykresie była Java!