18650. Java vs. Python vs. C

На этот статья посвящена не столько проблемам аккумулятора, сколько проблемам применения языков программирования.

Сначала анекдотичный случай из жизни. Один молодой человек пишет:

Мне сейчас 11 лет и у меня задача — к 14 знать 2-3 языка программирования (я сам себе такую задачу поставил).

Я сейчас уже достаточно хорошо владею JS, на изучение ушло 1.5 месяца (html и css в список входит) …

Не-е, вы — лохи — поняли, как надо изучать языки?!

Полтора месяца, и ты — крутой разработчик. Бингоу!!!

Я специально не уточняю ни имя парня, ни ресурс, где это я взял. Парень не плохой. Очень даже не плохой, если в 11 лет он уже задаётся такими вопросами. И я бы его всячески «плюсанул» за его жизненную позицию. Молодец, парниша! Правильно дорогой топаешь!

Однако. Я к чему привёл этот анекдотичный пример — а таких примеров по жизни полно! Как правило, люди обычно судят о своих способностях весьма субъективно. Я тоже неправильно оцениваю свои программистские способности. Я сделан из такого г*вна, как и все, ничем не отличаюсь в лучшую сторону.

У меня сейчас масса свободного времени и я ничем, абсолютно ничем не занят. Поэтому я по тихонечку я осваиваю Джаву. Не пинайте и не спрашивайте — зачем мне это надо!

В общем, так получилось, что я решил попробовать решить ту же задачу (вычисления ёмкости аккумулятора) на Джаве.

Чтобы не листать блог, я еще раз приведу пример кода на Питоне:

#!/usr/bin/env python3
#coding:utf-8

''' lion-cap.py '''

import sys

if __name__ == "__main__":
  with open(sys.argv[1], 'r') as f:
    lion = f.readlines()

  cap = 0.0
  for l in lion:
    cap += int(l.split()[2])

  print (cap * 0.0002646 / 3600)

А вот примерно тот же функционал, написанный на Джаве:

/**
* lion-cap.java
*/
import java.io.*;


class LionCharge
{
  public static void main(String[] args)
  {
    if (args.length == 1)
    {
      try
      {
        double cap = 0.0;
        String line;

        BufferedReader br = new BufferedReader(
                              new InputStreamReader(
                                new FileInputStream(args[0])));
        
        while ((line = br.readLine()) != null)
          cap += Integer.parseInt(line.split(" ")[2]);
        
        System.out.println("Ёмкость = " + (cap * 0.0002646 / 3600));
      }
      catch (IOException e)
      {
        System.err.println("Не могу прочитать файл " + args[0]);
        System.exit(0);
      }
    }
  }
}

Первое, что бросается в глаза, — это количество букв значительно больше. Да, Джава не отличается лаконичностью. Но это, отнюдь, не проблема!

Я уже как-то сравнивал проги, написанные на Питоне, Джаве и на Си. По скорости исполнения примерно они относились как 6:2:1, соответственно. То есть Питон на той задаче оказался примерно раза в три медленнее Джавы.

На этот раз, при подсчете ёмкости аккумулятора, в скорости продула Джава. Вот сравните:

alex@c18:~/test/java/lion$ time java LionCharge lion.l15
 Ёмкость = 1.9194097229999998

real 0m0.170s
 user 0m0.144s
 sys 0m0.016s

и

alex@c18:~/test/java/lion$ time ./lion-cap.py lion.l15
 1.9194097229999998

real 0m0.085s
 user 0m0.068s
 sys 0m0.004s

Конечно, это сравнение языков некорректное, и я отдаю себе отчёт в том, что я делаю.

Но, с другой стороны, — пацаны, давайте посмотри на эту проблему более широко! Разве Джава предназначена для таких мелких задач? — Нет, конечно! Джава, предназначена для решения более сложных и более запутанных проблем.

И наоборот — разве на Питоне можно легко создавать «габаритные» программы? — Тоже нет! Питон, как мне кажется, предназначен для небольших программ (типа этой), количество строк которых не превышает нескольких сотен.

Не-е, конечно, на спор можно написать на Питоне и громадные программы, в несколько десятков файлов, общей длинной несколько тысяч строк. Но, знаете, создавать, а потом поддерживать такую программу «Я что-то, Славик, очкую!». Я уже пробовал создавать на Питоне проги более 1000-2000 строк. Пока держишь в голове контекст задачи, вроде как что-то даже получается. Но проходит несколько месяцев, ты решаешь добавить функционал в прогу, и тут начинается та-акое, что «закапывание и вновь откапывание стюардессы» сваливается в ранг детских проблем. Казалось бы, добавление какой-нибудь незначительной фичи, превращает весь Питоновский код в какой-то малопотребный фарш. Вообще, в этом случае употребляют слово «в лапшу», но «лапша» относится всё же к процедурным языкам, а мои проги на Питоне, больше смахивают на ООП.

В общем, я так думаю, что Питон хорош на мелких программах. На программах, которые пишутся для себя, пишутся один раз для какой-то конкретной узкой задачи. Писать большие проги на Питоне, да ещё и «в продакшин» — ну, не знаю! Мне кажется, что это не совсем правильное решение.

Вот, примерно по этой самой причине я приостановил своё погружение в Питон, и занялся дайвингом в Джаве. Это не значит, что я задвинут Питон. Нет! Я освоил Питон для того уровня, который мне нужен для решения моих задач. Дальнейшее углубление не принесёт мне пользы. Я и впредь буду продолжать использовать Питон в своих работах типа этой — посчитать ёмкость аккумулятора, или для задачи рассчитать номиналы резисторов для стабилизатора, или посчитать индуктивность для источника питания. Тут и в самом деле, равных Питону нет!

Так что Питон отлично рулит в области, где требуется быстро написать небольшое приложение и быстро-быстро получить результат. Форма представления результата, так сказать — презентабельность — не имеет значения. Важно не то, как будет выглядеть результат на экране, важно получить результат в любом виде как можно быстрее.

Время написания программы и время работы (run-time) программы суммируются. И если даже программа (написанная, например, на Джаве) выдаст результат за 10 секунд, а программа, написанная на Питоне будет тупить минуту, то всё равно выиграет Питон. Потому, что написать и отладить прогу на Питоне займет полчаса. А на писать точно такую же прогу на Джаве и отладить её — час.

Ну вот как-то так — выбирайте для решения правильные инструменты!

Другое дело, что пока сам не попробуешь забывать гвозди пассатижами, и не убедишься, что молотком это делать эффективнее, фиг кто тебе сможет авторитетно посоветовать! Ну, вы поняли!

Update 17.10.2016

Не удержался я и написал версию проги на Си:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


#define BUFSIZE (100)

void proc(FILE *f)
{
  char buf[BUFSIZE];
  char *s, *pval;
  int value;
  double cap;
  
  cap = 0.0;
  
  while (!feof(f))
  {
    s = fgets(buf, BUFSIZE, f);
    
    if (s != NULL)
    {
      // printf("%d. %s", ++i, s);
      pval = strchr(s, ' '); // Указывает на вторую колонку
      if (pval != NULL)
      {
        pval = strchr(++pval, ' ');  // Указывает на третью колонку
        if (pval != NULL)
        {
          value = atoi(pval);
          cap += value;
        }
      }
    }
  }
  
  // printf("Ёмкость аккумулятора = %0.16f\n", cap * 0.0002646 / 3600);
  printf("Ёмкость аккумулятора = %f\n", cap * 0.0002646 / 3600);
}


int main(int argc, char *argv[])
{
  FILE *f;
  
  if (argc != 2)
  {
    fprintf(stderr, "Укажите имя файла с данными Li-аккумулятора\n");
    exit(EXIT_FAILURE);
  }
  
  f = fopen(argv[1], "r");
  if (!f)
  {
    fprintf(stderr, "Не могу открыть файл %s\n", argv[1]);
    exit(EXIT_FAILURE);
  }
  
  proc(f);
  
  fclose(f);
  
  return EXIT_SUCCESS;
}

И вот, что из этого вышло:

alex@c18:~/work/zhevak/lion/log$ time ./lion-cap lion.l15
Ёмкость аккумулятора = 1.919410

real 0m0.005s
user 0m0.000s
sys 0m0.000s

Ну ичо? Кто бы спорил, что Си уделает все другие реализации по скорости? Конечно уделает, и в этом нет никаких сомнений. Но, вот, объем Си-шного исходного кода… это философское протяжное «да-а!» на выдохе.

Это ж сколько времени (относительно Питона или Джавы) потребуется для написания Си-шной реализации? А сколько — для отладки!? А если учесть, что прога пишется не «на продажу» и не для широкого использование, а чисто для себя и для запуска всего лишь несколько раз (а потом её благополучно положим на хранение), то становится предельно ясно, что писать на Си такие проги — не просто дорого, а неразумно дорого.

Хотя, надо отдать должное — Си-шная прога работает чрезвычайно быстро! М-м!!! Пальчики оближешь!

8 responses to “18650. Java vs. Python vs. C

  1. Я похоже нашёл то, что заменит мне всё из вышеперечисленного, да ещё и отличные веб-приложения на нём можно делать, это гугловский язык Go, искать по нему информацию нужно по слову «golang».

    Вот пример этой же программы:

     
    	package main
    	import (
    		"fmt"
    		"io/ioutil"
    		"os"
    		"strings"
    		"strconv"
    	)
    	func main() {
    		content, _ := ioutil.ReadFile(os.Args[1])
    		lines := strings.Split(string(content), "\n")
    		var cap int64
    		for _, line := range lines {
    			fields := strings.Split(line, " ")
    			if len(fields)>1 {
    				num, _ := strconv.ParseInt(fields[2], 10, 64);
    				cap += num
    			}
    		}
    		fmt.Println(float64(cap) * 0.0002646 / 3600)
    	}
    

    Здесь игнорируются ошибки считывания файла и конвертации текстовых данных в число, если потребуется, это два дополнительных if-а.
    Скомпилировал эту программу за долю секунды в исполняемый файл размером 1.6 МБ. 10000 строк в test.txt обработал за мизерное время:

    	$ time ./lioncharge test.txt
    	0.016170808499999998
    	
    	real	0m0.033s
    	user	0m0.016s
    	sys	0m0.000s
    

    Можно было бы и не компилировать, а запускать как интерпретатор через «go run lioncharge.go», в этом случае компилируется во временную директорию. А если добавить в начало файла строку

    //usr/bin/env go run $0 $@; exit
    

    и сделать файл исполняемым, то можно запускать ./lioncharge.go test.txt, тайминг в этом случае увеличится на время компиляции файла, то есть, как у питона:

            $ time ./lioncharge.go test.txt
    	0.016170808499999998
    	
    	real	0m0.286s
    	user	0m0.184s
    	sys	0m0.052s
    

    У языка Go изумительный синтаксис, хоть он взят от си, но благодаря небольшому новшеству, как автоматическая расстановка ; в конце строк по определённому правилу, получаем стандарт форматирования блоков {}, и практически отсутствие ; в исходных кодах, так же отсутствие скобок у if и for (который заменяет все виды циклов) делает более читаемые тексты. И компилирует в исполняемый файл без привязки к библиотекам под любую операционную систему, я это собирал в линуксе, но можно взять этот код, и скомпилировать его в виндовсе, или макоси, и он будет работать.

    Советую обратить пристальное внимание к этому языку, он уже состоялся, используется во многих крупных проектах, есть огромное количество библиотек кода. Устанавливаются библиотеки одной командой, например:

    	$ go get github.com/russross/blackfriday
    

    Библиотека будет скачана в директорию, указанную в $GOPATH (единственное что приходится настроить), и автоматически компилируется, после этого её можно использовать в своём проекте, подключив в блоке import по полному имени, начиная с адреса сайта, где она располагается, аналогичным образом можно обновлять версии библиотек.

    Теперь можно создавать программы как на си, но писать и запускать их так же просто как в скриптовых языках навроде питона, но выполнять эту программу можно и в не настроенной среде, лишь бы платформа была подходящей.

    • Вот это да! Целая статья получилась!

      Я поправил форматирование исходного текста. Так же поправил запуск команду повторного запуска измерения времени.

      А вообще, спасибо за коммент! Не ожидал получить такой развёрнутый ответ.

  2. Поправка ошибки, второй тайминг начинается с: $ time ./lioncharge.go test.txt
    И конечно же кавычки в коде заменить на обычные, форматирование убило так же и отступы в коде.

  3. Вот ещё что, для работы с гигантскими числами есть стандартная библиотека https://golang.org/pkg/math/big/

    • Вау! Вот это поворот!!!

      Топнул по ссыке, открылась страница, начал читать. Прошёл-пролетел примерно пол-страницы. Супруга из кухни окликнула «Ты есть вообше идешь? Суп уже остыл!» Ответил «Щас, иду!» Поворачиваю голову опять к экрану — что за фигня! Весь текст стал английским. Хренасе! Вот, это же только-что произошло! Я же отдаю себе отчет, что я же чётко его читал по русски. Как так!? Вот, это эффект!

      Пойду-ка я лучше на кухню…

  4. Вот это я накосячил!!! Вместо того, чтобы ответить на комментарий Nobody, я безвозвратно затер его содержимое и написал ответ.

    >> Если серьёзно решили взяться за изучение языка Java…
    Я не уверен, что это есть мое серьёзное решение.

    Дело в том, что как таковой цели нет. А раз цели нет, то о чём вообще можно говорить.

    Наверно лучше сказать так: у меня сейчас затянувшееся экономическое затишье (безработица), вот я и заполняю паузу тем, что неспешно пробую новые для себя технологии.

    Уверенное решение заниматься той или иной технологией придёт тогда, когда появятся деньги, заказы. А сейчас… как оно самое в проруби! Никому ничего не надо, все затаились и чего то выжидают.

    Да, и вообще, бабло куда-то из региона ушло. Долги по зарплате в регионе только растут.

    Ну, что это такое: на e1.ru количество вакансий электронщика в сентябре было 4-5. А сейчас — вообще одна вакансия висит, и та недельной давности! Это для города-то миллионника! Это нормально? Или как?

    У заказчиков денег нет. На тему разработки электроники и программирования — никому ничего не надо. Заказов нет. Вакансий — нет. Чем зарабатывать на жизнь — вообще не понятно!

    К стати — http://www.yaplakal.com/forum7/topic1470216.html
    А мне уже 54. «Только старый парикмахер никому не нужен на…» (с)

    Может не Джаву нужно изучать, а вообще запасаться тушенку, соль, спички…

    А по делу — ну да, синтаксис одного языка мало чем отличается от синтаксиса другого языка. И там, и там циклы. И там, и там if-ы. И там, и там вызовы функций-методов. И там, и там классы. Основные вопросы при написании программ связаны с организацией ввода-вывода, конвертацией текста в integer-ы, обработкой массива, организацией взаимодействия потоков исполнения. Мне ещё приходится решать вопросы получения данных от внешних устройств через последовательный порт. Я пока не очень силён как это делается в Джаве. На Питоне этот вопрос снимается легко. На чистом Си — несколько больше приходится писать текста, но тоже не проблема. А вот на Джаве я зубксовал.

    Следующий вопрос — на чём лучше писать дексктоп-овские графические программы для получения данных от внешних устройств и отображения их (данных) на экране — не Джаве или на Qt?

    Пока сам не попробуешь, как оно это — самому месить тесто и печь пирожки, мало кто тебе сможет объяснить, как правильно это нужно делать для твоего конкретного случая.

  5. К сожалению, как только сложность программы переступает через некоторый порог, который зависит разработчика, то язык написания программы перестаёт быть важным.

    Для себя вывел простое правило: Писать код надо очень просто, код должен быть понятным, даже если тебя ночью бухим попросили что-то в нём поправить, ты должен быть способен его быстро понять, вспомнить и исправить. То есть, всё бьём на модули, но без фанатизма, все функции и методы — максимум с экран, переменные и функции названы понятно, никаких крутых фич в алгоритме, в сомнительных местах писать комментарий.

    В общем, прописные истины, но их нарушают в 95% проектов, которые я видел.

    Python или Java? Проект на Java дороже поддерживать и разработчики на этом языке дороже, а по вменяемости в среднем по палате они как и везде болеют теми же болезнями. А то, что Python немного проигрывает по скорости, это не беда. Можно критичные части вынести в C или просто докупить железа, оно щас дешевле чем труд разработчика.

    • Вот, на моём этом конкретном примере обработки этих конкретных данных от аккумуляторов хорошо видно, что скорость обработки вообще ни на что не влияет. Влияет — скорость создания программного продукта и получения результата (достижение цели).

      Джава, Питон или какой либо другой язык программирования — принципиально позволяют достичь цели — создать программный продукт, который посчитает и выведет на экран число. Причём скорость расчета в подобных случаях будет несоизмеримо меньше, чем время создания программы.

      Таким образом, получается, что для создания таких вот коротких программ наиболее хорошо себя показывает Питон. Джава проигрывает в скорости создания и сложности написания кода — в ней слишком много нужно соблюдать условностей (типа соблюдения типов переменных, всякике private-public спецификаторы видимости, @Override ну и так далее).

      Для больших сложных программ эти условности оказывают положительный («дисциплинирующий») эффект. А вот в небольших программках, эти условности становятся лишними.

      Недавно где-то прочитал красивую фразу. Попробую воспроизвести её по память, как запомнил.

      Хорошо написанная программа, как и хорошая шутка, не нуждается в комментариях. (с) не моё! Автора не запомнил.

      Это особенно актуально для коротких программок.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s