Почему Java в этом случае быстрее (и медленнее), чем C? - PullRequest
3 голосов
/ 23 июля 2011

Кто-то из студентов только начал изучать C, читая K & R, и предложил цикл преобразования по Фаренгейту в Цельсий, напечатанный на первых страницах:

#include <stdio.h>

main ()                                                                                                                                                       
{
  int fahr;                                                                                                                                                    

  for (fahr = 0; fahr<= 200000000; fahr = fahr + 20)                                                                                                                                                                                
    printf("%d\t%6.2f\n", fahr, (5.0 / 9.0) * (fahr-32));                                                                                                                                                                                       
}   

Ему сказали, что Java работает медленно.Итак, сказал ему, что Java очень конкурентоспособна в наши дни, но C в этом простом случае, вероятно, будет быстрее.Хотел его доказать и в основном добавил "System.out".перед printf ().

Это было более чем в 10 раз медленнее.Слишком много.Я был сбит с толку.Мысль о создании объекта String, GC, -server, yada, yada, yada.

Я был еще более озадачен, когда узнал, что почти 100% времени фактически было потрачено в printf () (PrintSteam.write(), выходные данные переданы в /dev/null).

После некоторой путаницы я пришел к этому (пока не выполняется округление% f):

public static void main(String... args) throws Exception {                                                                                                       
   int fahr=0;                                                                                                                                                    

    PrintWriter out = new PrintWriter(Channels.newWriter(Channels.newChannel(System.out), "US-ASCII") );                                                                                                

    int max = 2000000000;                                                                                                                                         
    for (fahr = 0; fahr<= max; fahr = fahr + 20)
      // out.printf("%d\t%6.2f\n", fahr, (5.0 / 9.0) * (fahr-32));                                                                                                       
      out.println( fahr + "\t" + f(((5.0 / 9.0) * (fahr-32)) ));                                                                                                        

    out.close();                                                                                                                                            
 }                                                                                                                                                                

 private static final String f(double d) {                                                                                                                         
      return (int)d + "." + (int)((d - (int)d)*100);                                                                                                              
 }                                                                                                                                                           
} 

Итак, это использует NIO,И превосходит gcc -O2 на двух протестированных машинах.

Вопросы:

  • Почему буквальный транскрипт с C на Java (то есть PrintStream) так медленно?
  • (почему прокомментировано out.printf() так медленно [возможно, производительность снижается со временем]?)
  • и, наконец: почему мое решение быстрее, чем C (вкл.Время запуска JVM)?

Ответы [ 2 ]

5 голосов
/ 23 июля 2011

почему буквальный транскрипт с C на Java (т. Е. PrintStream) такой медленный?

Вы тестируете System.out и различные реализации stdio (C vs Java)

(почему закомментировано out.printf () так медленно [возможно, производительность со временем снижается]?)

Преобразование числа с плавающей точкой в ​​строку (инаоборот) это очень сложная и медленная операция.Взгляните на исходный код glibc.

и, наконец, почему мое решение быстрее, чем C (включая время запуска JVM)?

Поскольку вы тестируете и тестируетесравнение разных вещей:

  • Java-код, который выполняет преобразование целого числа в строку (что по очевидным причинам намного быстрее, чем с плавающей запятой) и некоторые тривиальные строковые операции, которые, мы надеемся, JavaВМ может работать очень хорошо, плюс out.println ()
  • против кода C, который запускает интерпретируемый язык на каждой итерации цикла (да, printf является интерпретатором для небольшого языка, для которого"% d \ t% 6.2f \ n" является программой) и выполняет преобразование с плавающей запятой в строку (что само по себе во много раз медленнее, чем целое число), плюс stdio.

Не ясно, используется ли версия C одинарной или двойной точности.

3 голосов
/ 23 июля 2011

В основном ваши эксперименты показывают, что вычисления здесь совершенно неактуальны, и подавляющее большинство времени тратится на форматирование и печать выходных данных. Таким образом, вы тестируете не производительность C и Java как языков, а другой код библиотеки форматирования строк (C, кажется, гораздо лучше оптимизирован) и то, как stdout подключен к реальной консоли (Java выигрывает здесь).

...