Выбор оружия, или сравнение различных языков программирования. Обзор языков программирования

В предыдущих частях была проделана реализация совершенно однотипного приложения на нескольких разных языках программирования. Сначала мы рассмотрели реализации на 10-ти самых часто употребляемых языков в разработке реальных проектов, а затем - такие же реализации на языках новых, или более экзотических, или имеющих ограниченные сферы применения. Целью такого сравнения было посмотреть как внешне, не предвзятым взглядом, выглядит однотипный код, когда он записан на разных языках.

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

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

Примечание : Не ищите какого-то скрытого смысла и подтекста в том порядке, в котором представлены различные языки - они описаны в том произвольном порядке, в котором они хронологически тестировались.

Задача

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

Для грубых оценок вполне пригодна задача рекурсивного вычисления чисел Фибоначчи. Эта функция настолько проста, что её формулировка будет просто показана в изложении кода на языке C.

Примечание (для дотошной публики) : Существуют 2 определения последовательности чисел Фибоначчи: а). F 1 =0, F 2 =1, F N =F N-1 +F N-2 и б). F 1 =1, F 2 =1, F N =F N-1 +F N-2 . Как легко видеть, эти последовательности сдвинуты на 1 член, так что не стоит ломать копья по этому поводу: можно использовать любую форму. Мы будем использовать 2-ю.

Существуют эффективные алгоритмы вычисления последовательности чисел Фибоначчи (циклические, слева направо). Мы же сознательно будем использовать неэффективную рекурсивную реализацию (справа налево), именно в той форме, как выражения записаны выше. При таком алгоритме задача как раз удовлетворяет требованию высогой степени роста вычислительной сложности, о которой было сказано ранее.

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

Многие языковые средства предполагают и предоставляют те или иные способы оптимизации выполнения (например, уровень оптимизации, указываемый компилятору). Там, где мне известны способы оптимизации выполнения, будет использоваться максимальный уровень оптимизации.

Запуск команд на хронометраж мы станем делать командами вида:

# time nice -19 <команда_fibo> 30
  • команда выполняется от root, чтобы позволить повысить приоритет (nice -9) задачи выше нормального, снизив дисперсию результатов;
  • хронометраж выполняется системной командой time (не будем вмешиваться в процесс временных измерений);
  • параметр (30, порядковый номер числа Фибоначчи) определяет размерность задачи, объём вычислений в зависимости от него нарастает экспоненциально.

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

Результаты выполнения могут радикально меняться в зависимости от версии используемых инструментальных средств (компилятора, интерпретатора). Поэтому в итогах выполнения будет показываться версия используемого программного обеспечения.

Язык C

Листинг 1. Реализация задачи на языке C (fibo_c.c):
#include unsigned long fib(int n) { return n < 2 ? 1: fib(n - 1) + fib(n - 2); } int main(int argc, char **argv) { unsigned num = atoi(argv[ 1 ]); printf("%ld\n", fib(num)); return 0; }

Выполнение:

$ gcc --version gcc (GCC) 4.8.2 20131212 (Red Hat 4.8.2-7) ... # time nice -19 ./fibo_c 30 1346269 real 0m0.013s user 0m0.010s sys 0m0.002s

Можно предположить, что приложение, компилированное из C кода, будет самым быстрым. Поэтому именно эти цифры мы станем использовать как базовые значения для сравнения.

C++

Реализация будет выглядеть так:

Листинг 2. Реализация на языке C++ (fibo_c.cc):
#include #include using namespace std; unsigned long fib(int n) { return n < 2 ? 1: fib(n - 1) + fib(n - 2); } int main(int argc, char **argv) { unsigned num = atoi(argv[ 1 ]); cout << fib(num) << endl; return 0; }

Из этого единого кода будет создано 2 приложения - компиляцией GCC и компиляцией Clang:

$ g++ -O3 fibo_cc.cc -o fibo_cc $ clang++ fibo_cc.cc -o fibo_cl

Выполнение приложения, собранного GCC:

# time nice -19 ./fibo_cc 30 1346269 real 0m0.014s user 0m0.012s sys 0m0.002s

Здесь время абсолютно равное случаю реализации C, в пределах статистической погрешности, что и следовало ожидать.

Выполнение приложения, собранного Clang:

$ clang++ --version clang version 3.3 (tags/RELEASE_33/final) Target: i386-redhat-linux-gnu Thread model: posix # time nice -19 ./fibo_cl 30 1346269 real 0m0.035s user 0m0.033s sys 0m0.001s

Здесь всё гораздо хуже! Это в 2.7 раза медленнее, чем для GCC. Но в объяснение этого может быть то, что в команде компиляции Clang вообще не устанавливалась опция оптимизации (-O...).

Java

Листинг 3. Реализация задачи на Java (fibo.java):
public class fibo { public static long fib(int n) { return n < 2 ? 1: fib(n - 1) + fib(n - 2); } public static void main(String args) { int num = new Integer(args[ 0 ]).intValue(); System.out.println(fib(num)); } }

Компиляция приложения выполняется в реализации OpenJDK:

$ java -version java version "1.7.0_51" OpenJDK Runtime Environment (fedora-2.4.5.1.fc20-i386 u51-b31) OpenJDK Server VM (build 24.51-b03, mixed mode) $ javac fibo.java $ ls -l *.class -rw-r--r-- 1 olej olej 594 Фев 15 16:09 fibo.class

Если то же самое проделать с оригинальном Oracle JDK, то временные результаты могут отличаться.

Выполнение:

# time nice -19 java fibo 30 1346269 real 0m0.176s user 0m0.136s sys 0m0.047s

Выполнение JVM байт-кода Java здесь в 13.5 раз медленнее, чем компилированного в машинные команды кода C.

Python

Аналогичный код на Python:

Листинг 4. Реализация на Python (fibo.py):
#!/usr/bin/python # -*- coding: utf-8 -*- import sys def fib(n) : if n < 2: return 1 else: return fib(n - 1) + fib(n - 2) n = int(sys.argv[ 1 ]) print("{}".format(fib(int(sys.argv[ 1 ]))))

Для этого кода (он написан в совместимом синтаксисе) мы можем также предложить 2 различных способа исполнения:

  • Python версии 2: $ python --version Python 2.7.5 # time nice -19 python fibo.py 30 1346269 real 0m1.109s user 0m1.100s sys 0m0.005s
  • Python версии 3: $ python3 --version Python 3.3.2 # time nice -19 python3 fibo.py 30 1346269 real 0m1.838s user 0m1.823s sys 0m0.009s

Первое, что здесь сразу бросается в глаза: Python 2 быстрее Python 3 на 65%. Это достаточно ожидаемо - это естественная плата за существенно расширенный синтаксис. Ряд публикаций показывают даже существенно большую разницу на определённых классах задач, до 2-х или 3-х раз.

А вот в сравнении с нативным компилированным кодом C Python 2 проигрывает до 100 (85) раз! Это тоже соответствует тому, что звучит в публикациях.

Ruby

Листинг 5. Реализация задачи на Ruby (fibo.rb):
#!/usr/bin/ruby # coding: utf-8 def fib(n) return n < 2 ? 1: fib(n - 1) + fib(n - 2) end puts fib(ARGV[ 0 ].to_i)

Выполнение:

$ ruby --version ruby 2.0.0p353 (2013-11-22 revision 43784) # time nice -19 ruby fibo.rb 30 1346269 real 0m0.566s user 0m0.554s sys 0m0.009s

Здесь время выполнения, на удивление (непонятно почему), почти в 2 раза (1.77) лучше, чем у Python, и медленнее нативного кода C примерно в 43 раза.

Perl

Листинг 6. Реализация задачи на Perl (fibo.pm):
#!/usr/bin/perl sub fib { my $n = shift; $n < 2 ? 1: fib($n - 1) + fib($n - 2) } $f = fib($ARGV[ 0 ]); print "$f\n";

Выполнение:

$ perl --version This is perl 5, version 18, subversion 2 (v5.18.2) built for i386-linux-thread-multi ... # time nice -19 perl fibo.pm 30 1346269 real 0m2.335s user 0m2.329s sys 0m0.002s

Здесь проигрыш нативному коду C составляет свыше 179 раз! Но это достаточно естественно и ожидаемо - Perl не язык для вычислений, и его ниша это текстовая обработка.

JavaScript

Листинг 7. Реализация на JavaScript (файл fibo.js):
#!/usr/bin/js -U var fib = function(n) { // функциональный литерал return n < 2 ? 1: fib(n - 1) + fib(n - 2); } print(fib(arguments[ 0 ]))

Выполнение приложения (начиная с уточнения версии):

$ js -v JavaScript-C 1.8.5 2011-03-31 # time nice -19 js fibo.js 30 1346269 real 0m0.689s user 0m0.683s sys 0m0.005s

Этот результат удивил: это почти те же цифры, что и у Ruby, и в 2 раза лучше, чем Python. От нативного кода C здесь отставание в 53 раза.

PHP

Эквивалент задачи, выраженный на языке PHP:

Листинг 8. Реализация PHP (файл fibo.php):
#!/usr/bin/php

Выполнение приложения:

$ php --version PHP 5.5.9 (cli) (built: Feb 11 2014 08:25:04) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies # time nice -19 php fibo.php 30 1346269 real 0m1.307s user 0m1.292s sys 0m0.013s

Это в 108 раз медленнее, чем эквивалентное C приложение.

Lua

Листинг 9. Реализация задачи на языке Lua (файл fibo.lua):
#!/usr/bin/lua fib = function(n) -- функциональный литерал if(n < 2) then return 1 else return fib(n - 1) + fib(n - 2) end end print(fib(arg[ 1 ] + 0))

Выполнение такого приложения (с проверкой версии Lua):

$ lua Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio > # time nice -19 lua fibo.lua 30 1346269 real 0m0.629s user 0m0.624s sys 0m0.003s

Это те же результаты, что и у JavaScript и Ruby.

bash

Можно ли организовать подобные вычисления в интерпретаторе bash, учитывая, что функции bash могут возвращать только значения кода завершения в пределах , т. е. в нашем смысле - не имеющие возвращаемых вычисленных значений? Прежде всего, можно организовать подобные вычисления, если сам скрипт будет рекурсивно вызывать свои копии. Вот только то и всего:

Листинг 10. Реализация задачи в bash (файл fido.sh):
#!/bin/bash if [ "$1" -lt "2" ] then echo "1" else f1=$($0 `expr $1 - 1`) f2=$($0 `expr $1 - 2`) echo `expr $f1 + $f2` fi

Я не рискну вызывать такое решение с аргументом 30 (как остальные варианты) - я просто не дождусь решения... Но выполняется такого скрипт вполне успешно:

$ bash --version GNU bash, version 4.2.37(1)-release (i486-pc-linux-gnu) … # time nice -19 ./fibo.sh 10 89 real 0m1.137s user 0m0.350s sys 0m0.475s # time nice -19 ./fibo.sh 12 233 real 0m2.979s user 0m0.935s sys 0m1.248s # time nice -19 ./fibo.sh 14 610 real 0m7.857s user 0m2.528s sys 0m3.166s

Получается, что скрипт bash вычисляет функцию от 8 столько же, сколько не очень «спешному» Perl требуется для вычисления функции от 29 (это при экспоненциальном то росте!):

# time nice -19 perl fibo.pm 29 832040 real 0m1.464s user 0m1.448s sys 0m0.004s

Практического смысла показанная реализация bash не имеет, но сама такая возможность интересна. Другой возможностью может быть искусственно организованная рекурсия (с очередью, стеком возвратов) при вызове функции внутри скрипта:

Листинг 11. Внутренняя рекурсия в bash (файл fido_f.sh):
#!/bin/bash declare -a res fib () { if [ "$1" -lt 2 ] then res[ $1 ]=1. else. fib `expr $1 - 1` let s=${res[ `expr $1 - 1` ]}+${res[ `expr $1 - 2` ]} res[ $1 ]=$s fi } res[ 0 ]=1 fib $1 echo ${res[ $1 ]}

Здесь уже совсем другие результаты:

# time nice -19 ./fibo_f.sh 30 1346269 real 0m0.157s user 0m0.037s sys 0m0.083s # time nice -19 ./fibo_f.sh 60 2504730781961 real 0m0.337s user 0m0.075s sys 0m0.167s

Для N=60 результат даже превосходит результаты выполнения нативного C кода. Но здесь мы просто наблюдаем результат обмана: при вычислениях сделана «оптимизация» и фактически рекурсивное вычисление выродилось в циклическое, не порождающее 2-х деревьев рекурсивных вызовов.

Есть много параметров по которым можно сравнивать языки программирования. Именно как языки, а не платформы. Популярность, инструменты разработки, область применения, позиция на рынке — это важно, но интересно именно посмотреть на языки сами по себе.
Причём пофигу на их парадигмы: и на Си можно писать в ООП стиле (GTK+ например) и на Java можно делать монады .
А как они именно в жизни?

Если вам хочется узнать какой язык популярнее то крайне советую вам почитать статью В поисках самого востребованного языка программирования откуда я нагло стырил КДПВ.

Я же хочу обратить ваше внимание на такие почти субъективные параметры:

1. Набор базовых аксиом.
Есть языки которые похожи на китайский — куча иероглифов. А есть такие как английский, где всего 26 букв, зато из них можно комбинировать слова а из слов предложения.
Очевидно что чем меньше таких вот базовых символов тем проще начать обучение. Но получается больше текста, да.
С другой стороны доводить набор букв до 1 и 0 тоже бессмысленно. Тут нужно подбирать компромис. В среднем во всех языках около 15ти операторов и до десяти базовых типов.
Аксиоматичную мощность можно посчитать и вывести коэффициент. Я даже нашёл какое-то сравнение мощности языков столетней давности .
Это вполне серъёзная и слегка научная задача годная для диссертации. Тут даже и графики красивые в маткаде можно нарисовать и из Википедии накопипастить заумных терминов. По крайней мере всерьёз годик разбираться.
Но вместо этого все пишут диссеры про какую то фигню, в лучшем случае о рефакторинге или RESTе. И кстати тоже не особо мудрённое дело для диссера: метод экстрактнуть или HTTP запрос отправить. Ловите намёк 😉

2. Читабельность.
Большую часть времени программисты читают код а не пишут.
Что такое читабельность начинаешь понимать когда сравниваешь код на питоне и на перле.
Тут такая закономерность: чем высокоуровневей язык программирования, тем лучше читаемость. SQL вообще читается как обычный текст.

3. Синтаксический сахар
Для часто повторяющихся примитивных вещей. Например, в яве строки — это объекты, и по хорошему нужно их конкатенировать вызовом метода. Но чтобы облегчить людям жизнь специально добавили синтаксический сахар когда оператор + выполняет конкатенацию строк.
Но плюс работает только для строк в виде исключения: всем остальным классам переопределять операторы нельзя, чтобы не было удивления в коде.
А вот в C++, C#, Groovy и многих других языках можно делать переопределение операторов и в результате потом часто удивляешься что это за фигня такая в коде: users << new User() пока не узнаёшь что добрые молодцы добавили сахару для добавления в список.
Вообщем, тут опять таки как с языками — если в английском жёсткая грамматика и порядок слов, то в русском пиши как хочешь и синтезируй слова.
В результате иностранцы не могут понять русский.

4. Возможность выстрелить в ногу.
Лучше всего стрелять в ногу на Си: тут ты выхватываешь настоящий Segmentation fault а не унылый NPE. Делишь 1/3 и получаешь 0. Пишешь if (x = 3) и долго удивляешься почему код не работает. И через переполненный буфер хакеры тебе валят сервак.
А ещё в Си бывают приколы когда из-за оптимизирующей опции компилятора программа перестаёт работать вообще.

5. Магия.
Магия это некая фича которая позволяет делать всякие трюки не предусмотренные изначально создателями.
Очень часто мы даже не задумываемся что используем магию.
Например, директивы прекомпилятора и макросы — ими можно и вовсе перевести C++ на олбанский:

#include #include #if !defined (_MSC_VER) || _MSC_VER < 1400 #error Wrong compiler! Use MSVS 8.0 #endif #define НАЧЕЛ { #define КОНЧЕЛ;} #define ТИПА int #define ВДРУГ if (#define ТАДА) #define НИХРИНА else #define ВЗАД return #define КАГДИЛА (#define ЙО; #define ЖЖОШ(p,n) for (; (p) <= (n); (p)++) #define БАЗАР std::cout << #define СЛЫШЬ << #define СТОЙ system ("echo. & pause"); #define БЛИН _wsetlocale (LC_ALL, L"Russian_Russia.ACP"); #define ВРОДЕ try #define ИБАНУЦЦО throw #define АПСТЕНУ catch (const char* __чё__) #define ПРЕВЕД ТИПА main КАГДИЛА ТАДА #define МЕДВЕД ВЗАД 0; КОНЧЕЛ ТИПА КРУТО КАГДИЛА ТИПА фигня ТАДА НАЧЕЛ БАЗАР "ВАЩЕ " ЙО ВДРУГ фигня == 8 ТАДА ИБАНУЦЦО "мля! " ЙО ВЗАД 0 КОНЧЕЛ ПРЕВЕД НАЧЕЛ БЛИН ВРОДЕ НАЧЕЛ ТИПА фишка = 0 ЙО ЖЖОШ (фишка, 10) НАЧЕЛ БАЗАР фишка СЛЫШЬ " "; ВДРУГ фишка >= 5 ТАДА КРУТО (фишка) ЙО КОНЧЕЛ КОНЧЕЛ АПСТЕНУ НАЧЕЛ БАЗАР "ИБАНУЦЦО invoked: " СЛЫШЬ __чё__; КОНЧЕЛ СТОЙ МЕДВЕД

Теперь давайте сравним языки по этим критериям:
Си
1. Минимальный базовый набор аксиом: В Си всё просто: вот функции, вот структуры, вот указатели, в атаку! Труъ сишники, типа Торвальдса, смотрят на плюсников как на позеров.
2. Читабельность: в Си она низкая i++, j—, for (;;) но сильно выручает что набор минимален.
3. Синтаксический сахар: квадратные скобочки для массивов (можно обойтись указателем) и строковые литералы.
4. В ногу вы просто стреляете: выходите за рамки буферов, забываете подчистить память, в результате имеете настоящий Segmentation fault.
5. Как это не удивительно без магии в Си не сделать ни шагу. Магия в Си — это директивы прекомпилятора. На них делается всё: инклдюды, константы, DSL’ы.

Си++
1. Тут уже появляются объекты, но с ними ещё куча свистелок и перделок по числу которых плюсы впереди планеты всей. Вообще появляется ощущение что плюсы тестовый полигон для всех всех концепций программирования.
2. Читабельность почти никакая. Местами спасает только Си-подобный синтаксис.
3. Сахарка хватает: даже хелоу ворлд начинается с переопределённого оператора << для cout.
4. Стреляем в ногу из пулемёта. Классика жанра — множественное наследование.
5. Магия достигается через шаблоны STL и Boost.

Ява
1. Тут просто взяли Си++ и убрали всё лишнее. В результате всё просто: вот класс, вот методы, создаёшь объект и дергаешь методы, если что-то пошло не так кидаешь исключение, «шо не йасно?».
Но всё равно перестарались: вложенные классы, статические методы, примитивные типы. Когда начинаешь готовится к сертификации OSCJP внезапно понимаешь что Явы ты не знаешь.
2. Синтаксис вполне уже читабельный, если не обращать внимание на реликты после Си. По сути lingva franca из-за чего её любят использовать в учебниках.
3. Если знаешь все приколы Си то в ногу стрельнуть уже довольно сложно. Разве что Out of memory или Null pointer exception. Собственно поэтому на Яве и написали кучу энтерпрайзного софта.
4. Магия постигается с помощью аннотаций, которые вообще то не должны влиять на программу. Но по факту по следам аннотаций потом курочат байт код до неузнаваемости.

Си шарп
1. Взяли яву и натащили всего нужного и ненужного в целях маркетинга. Чем структуры отличаются от классов? Зачем нужен yield ? Судя по всему он и не так часто используется .
3. Опять переопределение операторов и прочий зоопарк из C++, но уже с уборщиком мусора.
2. Читабельность нормальная. Ну примерно как у Делфи (создатель один и тот же).
4. Для магии всегда придумывают целые технологии, типа LINQ.

Пайтон
1. Большой набор базовых принципов которые плохо подобраны.
2. Читабельность хорошая — издалека вообще со стихами Маяковского можно спутать.
4. Магия достигается использованием сишных либ которые всё умеют. Поэтому на питоне написано половина гуёв на линуксах.
Вообще про питон лично я ничего хорошего не могу сказать — я на нём написал с десяток скриптов и каждый раз это было отстойно. Может в нём и есть какая фишка.

Перл
2. Перл получился в процессе эволюции текстового редактора. И бесспорно имеет самый ужасный write-only синтаксис. Регулярные выражения как раз пришли из перла, что о многом говорит. Мне кажется создатели Brainfuck просто немного упростили Perl.
4. Магия перла в том что одной строчкой можно переколбасить весь текст в документе.

Руби
По сути — объектно-ориентированный Перл.
1. Синтаксис настолько засахаренный что можно получить диабет.
2. Читабельность как у перла, но выручает единообразие — главное понять концепцию.
4. Магия достигается с помощью метапрограммирования поверх динамизма. Например, если вы дёргаете метод которого нет, то можно его перехватить и всё таки выполнить. Так делают динамик файндеры, например.
Всё что в книжках по яве написано «так делать нельзя» в руби пишут «смотрите, можно даже так сделать!».

Ada
Аду создавали в рамках конкурса для армии США. Т.е. изначально попросили академиков придумать самый крутой язык программирования. За что боролись на то и напоролись.
1. Базовый набор огромен. До появления Scala это был самый богатый язык программирования.
2. При этом великолепный читабельный паскальный синтаксис.
3. Сахару достаточно.
4. Магии практически нет — всё итак уже в языке. Хотя тут я не уверен, я не так много кода видел на Аде.

Я не просто так упомянул Аду, почитайте её критику:

Хоар выразил своё сожаление тем, что «погремушки и побрякушки возобладали над фундаментальными требованиями надёжности и безопасности» и предостерёг от «армады ракет, летящих не туда из-за не обнаруженной вовремя ошибки в компиляторе Ады». Никлаус Вирт высказался более сдержанно, но тоже негативно. Он сказал: «Слишком много всего вываливается на программиста. Я не думаю, что, изучив треть Ады, можно нормально работать. Если вы не освоите всех деталей языка, то в дальнейшем можете споткнуться на них, и это приведёт к неприятным последствиям». Жан Ишбиа, руководитель группы разработчиков Ады, выразив своё «уважение и восхищение» Виртом, не согласился с ним, сказав: «Вирт верит в простые решения сложных проблем. Я не верю в такие чудеса. Сложные проблемы требуют сложных решений».

Стоит ли говорить что в результате Ада в жопе а в космос летает софт написанный на Сишечке?

Scala
Скала это попытка сделать Яву функциональной в ущерб здравому смыслу.
Точно так же как и Аду её придумали искусственно в «лаборатории по созданию языков программирования» что уже должно настораживать.
Как и любая функциональщина, она доводит до оргазма всяких умников с «математическим складом ума».
Нормальным инженерам становится страшно когда они представляют как поддерживать проект на Скале. Scala хуже, чем Java. Как минимум, для половины Java проектов .

Очень хорошо это описано в статье Андрея Платова О выборе языка программирования :

Scala даст огромный рост продуктивности по сравнению с Java (так же как C->C++). Это верно для проекта с одним автором в вакууме. Сложность, и безграничные возможности языка отразятся гемороем, который нихера не будет способствовать продуктивности. Вопрос только в том чего будет больше. Я пока не знаю, да и больших Scala проектов в мире по большому счету еще нет.

Вывод: я пришёл к такому же выводу как Андрей Платов — мы сейчас находимся во время ломки языков программирования и реально выбирать на самом деле не из чего — все текущие языки явно морально устаревшие.
Нужно совершенно новое поколение языков программирования. Да такое чтобы все текущие языки показались такой же глупой затеей как писать на перфокартах.
Но об этом я позже.

Ещё по теме

PS

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

Не поленитесь, и почитайте ещё несколько очень важных моих .
Также не забудьте вступить в группу IT Juniors куда я пытаюсь собирать ссылки на другие полезные статьи для вас и анонсы курсов и интернатуры в компаниях.

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Министерство высшего специального образования Российской федерации

Федеральное агентство по образованию

ОГИЭТ

РЕФЕРАТ

по дисциплине: Информатика

на тему: «Сравнительный анализ языков программирования»

Введение

Машинный код процессора

Алгоритм и программа

Что такое язык программирования

Компиляторы и интерпретаторы

Уровни языков программирования

Поколения языков программирования

Обзор языков программирования высокого уровня

Языки программирования баз данных

Языки программирования для Интернета

Языки моделирования

Прочие языки программирования

Заключение

Список используемой литературы

Введение

Появление первых компьютеров породило программирование как науку. Разрабатывались первые математические теории обработки информации, средства доказательства правильности программ, оптимизации кода, создания эффективных компиляторов, формального тестирования и т. д. Затем, с появлением универсальных языков программирования третьего поколения, эти аспекты стали менее актуальными - исследования шли и идут в основном в области автоматической генерации исходных текстов и повышения эффективности компиляторов. Программирование превратилось в искусство - миллионы людей, не имевших специального образования, получили возможности применять компьютеры для решения собственных прикладных задач, что потребовало от них мастерства создавать правильно работающие программы. Искусством программирование остается и сегодня для профессиональных разработчиков и любителей, создающих программы в одиночку или в небольших компаниях, где все решает индивидуальное мастерство.

Машинный код процессора

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

В электронике транзисторы имеют три применения: для создания усилителей, в электронных схемах, обладающих автоколебательными свойствами, и в электронных переключателях. Последний способ и применяется в цифровой вычислительной технике. В процессоре компьютера транзисторы сгруппированы в микроэлементы, называемые триггерами и вентилями. Триггеры имеют два устойчивых состояния (открыт - закрыт) и переключаются из одного состояния в другое электрическими сигналами. Этим устойчивым состояниям соответствуют математические понятия 0 или 1. Вентили немного сложнее -- они могут иметь несколько входов (напряжение на выходе зависит от комбинаций напряжений на входах) и служат для простейших арифметических и логических операций.

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

Алгоритм и программа

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

Что такое язык программирования

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

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

Языки программирования - искусственные языки. От естественных они отличаются ограниченным числом «слов», значение которых понятно транслятору, и очень строгими правилами записи команд (операторов). Совокупность подобных требований образует синтаксис языка программирования, а смысл каждой команды и других конструкций языка - его семантику. Нарушение формы записи программы приводит к тому, что транслятор не может понять назначение оператора и выдает сообщение о синтаксической ошибке, а правильно написанное, но не отвечающее алгоритму использование команд языка приводит к семантическим ошибкам (называемым еще логическими ошибками или ошибками времени выполнения).

Процесс поиска ошибок в программе называется тестированием, процесс устранения ошибок - отладкой.

Компиляторы и интерпретаторы

программирование язык компилятор интерпретатор

С помощью языка программирования создается не готовая программа, а только ее текст, описывающий ранее разработанный алгоритм. Чтобы получить работающие программу, надо этот текст либо автоматически перевести в машинный код (для этого служат программы-компиляторы) и затем использовать отдельно от исходного текста, либо сразу выполнять команды языка, указанные в тексте программы (этим занимаются программы-интерпретаторы).

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

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

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

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

С помощью интерпретатора, наоборот, допустимо в любой момент остановить работу программы, исследовать содержимое памяти, организовать диалог с пользователем, выполнить сколь угодно сложные преобразования данных и при этом постоянно контролировать состояние окружающей программно-аппаратной среды, благодаря чему достигается высокая надежность работы. Интерпретатор при выполнении каждого оператора проверяет множество характеристик операционной системы и при необходимости максимально подробно информирует разработчика о возникающих проблемах. Кроме того, интерпретатор очень удобен для использования в качестве инструмента изучения программирования, так как позволяет понять принципы работы любого отдельного оператора языка.

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

Уровни языков программирования

Разные типы процессоров имеют разные наборы команд. Если язык программирования ориентирован на конкретный тип процессора и учитывает его особенности, то он называется языком программирования низкого уровня. В данном случае «низкий уровень» не значит «плохой». Имеется в виду, что операторы языка близки к машинному коду и ориентированы на конкретные команды процессора.

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

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

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

Поколения языков программирования

Языки программирования принято делить на пять поколений. В первое поколение входят языки, созданные в начале 50-х годов, когда первые компьютеры только появились на свет. Это был первый язык ассемблера, созданный по принципу «одна инструкция - одна строка».

Расцвет второго поколения языков программирования пришелся на конец 50-х - начало 60-х годов. Тогда был разработан символический ассемблер, в котором появилось понятие переменной. Он стал первым полноценным языком программирования. Благодаря его возникновению заметно возросли скорость разработки и надежность программ.

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

С начала 70-х годов по настоящее время продолжается период языков четвертого поколения. Эти языки предназначены для реализации крупных проектов, повышения их надежности и скорости создания. Они обычно ориентированы на специализированные области применения, где хороших результатов можно добиться, используя не универсальные, а проблемно-ориентированные языки, оперирующие конкретными понятиями узкой предметной области. Как правило, в эти языки встраиваются мощные операторы, позволяющие одной строкой описать такую функциональность, для реализации которой на языках младших поколений потребовались бы тысячи строк исходного кода.

Рождение языков пятого поколения произошло в середине 90-х годов. К ним относятся также системы автоматического создания прикладных программ с помощью визуальных средств разработки, без знания программирования. Главная идея, которая закладывается в эти языки, - возможность автоматического формирования результирующего текста на универсальных языках программирования (который потом требуется откомпилировать). Инструкции же вводятся в компьютер в максимально наглядном виде с помощью методов, наиболее удобных для человека, не знакомого с программированием.

Обзор языков программирования высокого уровня

FORTRAN (Фортран). Это первый компилируемый язык, созданный Джимом Бэкусом в 50-е годы. Программисты, разрабатывавшие программы исключительно на ассемблере, выражали серьезное сомнение в возможности появления высокопроизводительного языка высокого уровня, поэтому основным критерием при разработке компиляторов Фортрана являлась эффективность исполняемого кода. Хотя в Фортране впервые был реализован ряд важнейших понятий программирования, удобство создания программ было принесено в жертву возможности получения эффективного машинного кода. Однако для этого языка было создано огромное количество библиотек, начиная от статистических комплексов и кончая пакетами управления спутниками, поэтому Фортран продолжает активно использоваться во многих организациях, а сейчас ведутся работы над очередным стандартом Фортрана Р2к, который появится в 2000 году. Имеется стандартная версия Фортрана НРF(High Performance Fortran) для параллельных суперкомпьютеров со множеством процессоров.

СОВО L (Кобол). Это компилируемый язык для применения в экономической области и решения бизнес - задач, разработанный в начале 60-х годов. Он отличается большой « многословностью » - его операторы иногда выглядят как обычные английские фразы. В Коболе были реализованы очень мощные средства работы с большими объемами данных, хранящимися на различных внешних носителях. На этом языке создано очень много приложений, которые активно эксплуатируются и сегодня. Достаточно сказать, что наибольшую зарплату в США получают программисты на Коболе.

Algol (Алгол). Компилируемый язык, созданный в 1960 году. Он был призван заменить Фортран, но из-за более сложной структуры не получил широкого распространения. В 1968 году была создана версия Алгол 68, по своим возможностям и сегодня опережающая многие языки программирования, однако из-за отсутствия достаточно эффективных компьютеров для нее не удалось своевременно создать хорошие компиляторы.

Paskal (Паскаль). Язык Паскаль, созданный в конце 70-х годов основоположником множества идей современного программирования Никлаусом Виртом, во многом напоминает Алгол, но в нем ужесточен ряд требований к структуре программы и имеются возможности, позволяющие успешно применять его при создании крупных проектов.

Basik (Бейсик). Для этого языка имеются и компиляторы, и интерпретаторы, а по популярности он занимает первое место в мире. Он создавался в 60-х годах в качестве учебного языка и очень прост в изучении.

С (Си). Данный язык был создан в лаборатории Bell и первоначально не рассматривался как массовый. Он планировался для замены ассемблера, чтобы иметь возможность создавать столь же эффективные и компактные программы и в то же время не зависеть от конкретного типа процессора.

Си во многом похож на Паскаль и имеет дополнительные средства для прямой работы с памятью (указатели). На этом языке в 70-е годы написано множество прикладных и системных программ и ряд известных операционных систем (11пгх).

С++ (Си ++). Си ++ - это объектно-ориентированное расширение языка Си, созданное Бьярном Страуструпом в 1980 году. Множество новых мощных возможностей, позволивших резко повысить производительность программистов, наложилось на унаследованную от языка Си определенную низкоуровневость, в результате чего создание сложных и надежных программ потребовало от разработчиков высокого уровня профессиональной подготовки.

Java (Джава, Ява). Этот язык был создан компанией 5ип в начале 90-х годов на основе Си ++. Он призван упростить разработку приложений на основе Си ++ путем исключения из него всех низкоуровневых возможностей. Но главная особенность этого языка - компиляция не в машинный код, а в платформно-независимый байт-код (каждая команда занимает один байт). Этот байт-код может выполняться с помощью интерпретатора - виртуальной java- машины JVM(Java Virtual Machine), версии которой созданы сегодня для любых платформ. Благодаря наличию множества Java-машин программы на Java можно переносить не только на уровне исходных текстов, но и на уровне двоичного байт-кода, поэтому по популярности язык Ява сегодня занимает второе место в мире после Бейсика.

Особое внимание в развитии этого языка уделяется двум направлениям: поддержке всевозможных мобильных устройств и микрокомпьютеров, встраиваемых в бытовую технику (технология Jini) и созданию платформно-независимых программных модулей, способных работать на серверах в глобальных и локальных сетях с различными операционными системами (технология Java Beans). Пока основной недостаток этого языка - невысокое быстродействие, так как язык Ява интерпретируемый.

С# (Си Шарп). В конце 90-х годов в компании Microsoft, руководством Андерса Хейльсберга был разработан язык С#. В нем воплотились лучшие идеи Си и Си ++, а также достоинства Java. Правда, С#, как и другие технологии Microsoft, ориентирован на платформу Windows. Однако формально он не отличается от прочих универсальных языков, а корпорация даже планирует его стандартизацию. Язык С# предназначен для быстрой разработки. NET-приложений, и его реализация в системе Microsoft Visual Studio. NET содержит множество особенностей, привязывающих С# к внутренней архитектуре Windows и платформы.NET.

Языки программирования баз данных

Эта группа языков отличается от алгоритмических языков прежде всего решаемыми задачами. База данных - это файл (или группа файлов), представляющий собой упорядоченный набор записей, имеющих единообразную структуру и организованных по единому шаблону (как правило, в табличном виде). База данных может состоять из нескольких таблиц. Удобно хранить в базах данных различные сведения из справочников, картотек, журналов бухгалтерского учета и т. д.

При работе с базами данных чаще всего требуется выполнять следующие операции:

§ создание/модификация свойств/удаление таблиц в базе данных;

§ поиск, отбор, сортировка информации по запросам пользователей;

§ добавление новых записей;

§ модификация существующих записей;

§ удаление существующих записей.

Первые базы данных появились очень давно, как только появилась потребность в обработке больших массивов информации и выборки групп записей по определенным признакам. Для этого был создан структурированный язык запросов SQL (Structured Query Language). Он основан на мощной математической теории и позволяет выполнять эффективную обработку баз данных, манипулируя не отдельными записями, а группами записей.

Для управления большими базами данных и их эффективной обработки разработаны СУБД (Системы Управления Базами Данных). Практически в каждой СУБД помимо поддержки языка SQL имеется также свой уникальный язык, ориентированный на особенности этой СУБД и не переносимый на другие системы. Сегодня в мире насчитывается три ведущих производителя СУБД: Microsoft(SQL Server), IВМ (DB2) и Огас1е. Их продукты нацелены на поддержку одновременной работы тысяч пользователей в сети, а базы данных могут храниться в распределенном виде на нескольких серверах. В каждой из этих СУБД реализован собственный диалект SQL, ориентированный на особенности конкретного сервера, поэтому SQL-программы, подготовленные для разных СУБД, друг с другом, как правило, несовместимы.

С появлением персональных компьютеров были созданы так называемые настольные СУБД. Родоначальником современных языков программирования баз данных для ПК принято считать СУБД dBase II, язык которой был интерпретируемым. Затем для него были созданы компиляторы, появились СУБД FoxPro и Clipper, поддерживающие диалекты этого языка. Сегодня самой распространенной настольной СУБД стала система Microsoft Access.

Языки программирования для Интернета

С активным развитием глобальной сети было создано немало реализаций популярных языков программирования, адаптированных специально для Интернета. Все они отличаются характерными особенностями: языки являются интерпретируемыми, интерпретаторы для них распространяются бесплатно, а сами программы - в исходных текстах. Такие языки называют скрипт-языками.

HTML . Общеизвестный язык для оформления документов. Он очень прост и содержит элементарные команды форматирования текста, добавления рисунков, задания шрифтов и цветов, организации ссылок и таблиц. Все Web-страницы написаны на языке HTML или используют его расширения.

Рег l . В 80-х годах Ларри Уолл разработал язык Реrl. Он задумывался как средство эффективной обработки больших текстовых файлов, генерации текстовых отчетов, и управления задачами. По мощности Perl значительно превосходит языки типа-Си. В него введено много часто используемых функций работы со строками, массивами, всевозможные средства преобразования данных, управления процессами, работы с системной информацией и др.

РНР . Расмус Лердорф, активно использовавший Perl-скрипты, в 1995 году решил улучшить этот язык, упростив его и дополнив встроенными средствами доступа к базам данных. В результате появилась разработка Personal Content Page/Forms Interpreter(PHP/FI). Уже через пару лет программы на ее основе использовались на 50 тыс. сайтов. В 1997 году ее значительно усовершенствовали Энди Гутмане и Зив Сураски, и под названием РНР 3.0 этот язык быстро завоевал популярность у создателей динамических сайтов во всем мире.

Tcl / Tk . В конце 80-х годов Джон Аустираут придумал популярный скрипт-язык Tcl и библиотеку Tk. В Tcl он попытался воплотить видение идеального скрипт-языка. Язык Tcl ориентирован на автоматизацию рутинных процессов и состоит из мощных команд, предназначенных для работы с абстрактными нетипизированными объектами. Он независим от типа системы и при этом позволяет создавать программы с графическим интерфейсом.

VRML . В 1994 году был создан язык VRML для организации виртуальных трехмерных интерфейсов в Интернете. Он позволяет описывать в текстовом виде различные трехмерные сцены, освещение и тени, текстуры (покрытия объектов), создавать свои миры, путешествовать по ним, «облетать» со всех сторон, вращать в любых направлениях, масштабировать, регулировать освещенность и т. д.

XML . В августе 1996 года WWW-консорциум, ответственный за стандарты на Интернет-технологии, приступил к подготовке универсального языка разметки структуры документов, базировавшегося на достаточно давно созданной в IВМ технологии SGML. Новый язык получил название XML. Сегодня он служит основой множества системных, сетевых и прикладных приложений, позволяя представлять в прозрачном для пользователей и программ текстовом виде различные аспекты внутренней структуры иерархически организованных документов. В недалеком будущем он может стать заменой HTML.

Языки моделирования

При создании программ и формировании структур баз данных нередко применяются формальные способы их представления - формальные нотации, с помощью которых можно визуально представить (изобразить с помощью мыши) таблицы баз данных, поля, объекты программы и взаимосвязи между ними в системе, имеющей специализированный редактор и генератор исходных текстов программ на основе созданной модели. Такие системы называются CASE-системами. В них активно применяются нотации IDEF, а в последнее время все большую популярность завоевывает язык графического моделирования UML.

Прочие языки программирования

PL / I (PL/I). В середине 60-х годов компания IВМ решила взять все лучшее из языков Фортран, Кобол и Алгол. В результате в 1964 году на свет появился новый компилируемый язык программирования, который получил название Programming Language One. В этом языке было реализовано множество уникальных решений, полезность которых удается оценить только спустя 33 года, в эпоху крупных программных систем. По своим возможностям PL/I значительно мощнее многих других языков (Си, Паскаля). Например, в PL/I присутствует уникальная возможность указания точности вычислений - ее нет даже у Си ++ и Явы. Этот язык и сегодня продолжает поддерживаться компанией IВМ.

Smalltalk (Смолток). Работа над этим языком началась в 1970 году в исследовательской лаборатории корпорации XEROX, а закончились спустя 10 лет, воплотившись в окончательном варианте интерпретатора SMALLTALK-80. Данный язык оригинален тем, что его синтаксис очень компактен и базируется исключительно на понятии объекта. В этом языке отсутствуют операторы или данные. Все, что входит в Смолток, является объектами, а сами объекты общаются друг с другом исключительно с помощью сообщений (например, появление выражения 1 + 1 вызывает посылку объекту I сообщения «+», то есть «прибавить», с параметром 1, который считается не числом-константой, а тоже объектом). Больше никаких управляющих структур, за исключением «оператора» ветвления (на самом деле функции, принадлежащей стандартному объекту), в языке нет, хотя их можно очень просто смоделировать. Сегодня версия VisualAge for Smalltalk активно развивается компанией IВМ.

LISP (Лисп). Интерпретируемый язык программирования, созданный в 1960 году Джоном Маккарти. Ориентирован на структуру данных в форме списка и позволяет организовывать эффективную обработку больших объемов текстовой информации.

Prolog (Пролог). Создан в начале 70-х годов Аланом Колмероэ. Программа на этом языке, в основу которого положена математическая модель теории исчисления предикатов, строится из последовательности фактов и правил, а затем формулируется утверждение, которое Пролог будет пытаться доказать с помощью введенных правил. Человек только описывает структуру задачи, а внутренний «мотор» Пролога сам ищет решение с помощью методов поиска и сопоставления.

Ada (Ада). Назван по имени леди Огасты Ады Байрон, дочери английского поэта Байрона и его отдаленной родственницы Анабеллы Милбэнк. В 1980 году сотни экспертов Министерства обороны США отобрали из 17 вариантов именно этот язык, разработанный небольшой группой под руководством Жана Ишбиа. Он удовлетворил на то время все требования Пентагона, а к сегодняшнему дню в его развитие вложены десятки миллиардов долларов. Структура самого языка похожа па Паскаль. В нем имеются средства строгого разграничения доступа к различным уровням спецификаций, доведена до предела мощность управляющих конструкций.

FORTH (Форт). Результат попытки Чарльза Мура в 70-х годах создать язык, обладающий мощными средствами программирования, который можно эффективно реализованным на компьютерах с небольшими объемами памяти, а компилятор мог бы выдавать очень быстрый и компактный код, то есть служил заменой ассемблеру. Однако сложности восприятия программного текста, записанного в непривычной форме, сильно затрудняли поиск ошибок, и с появлением Си язык Форт оказался забытым.

Заключение

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

Список используемой литературы

1. Симонович С. В. Информатика базовый курс 2-е издание «Питер» М., Санкт - Петербург, Ростов-на-Дону-2006

2. А.А. Степанов Информатика 4-е издание «Питер» М., Санкт - Петербург, Ростов-на-Дону, Киев-2005

3. Б.В. Соболь, А. Б. Галин Информатика учебник Ростов-на-Дону, «Феникс» 2005

4. И.И. Сергеева, А.Р. Музалевская Информатика, М. Форум-Инфа-Москва, 2006

5. Е.Л. Жукова, Е.Г. Бурда Информатика, М. 2007, Наука-Пресс

Размещено на Allbest.ru

Подобные документы

    Понятия структурного программирования и алгоритма решения задачи. Краткая история развития языков программирования от машинных до языков ассемблера и языков высокого уровня. Процедурное программирование на C#. Методы и программы для моделирования.

    учебное пособие , добавлен 26.10.2010

    Сущность и функции языков программирования, их эволюция и оценка популярности различных видов. Особенности компьютерных программ, разработанных на компилируемом, интерпретируемом или смешанном языке. Основные классы и иерархия языков программирования.

    презентация , добавлен 23.01.2013

    Эволюция языков программирования от низкого уровня до современности. Языки программирования второго поколения - ассемблер. Императивные, функциональные, логические и объектно-ориентированные языки. Машинная независимость. Парадигмы программирования.

    презентация , добавлен 14.10.2013

    Классификация языков программирования. Использование циклических конструкций и выполнение итерационных процессов. Алгоритмические структуры циклов языков C, C++, Java, C#. Особенности современных языков программирования высокого уровня и их применение.

    курсовая работа , добавлен 13.11.2009

    Характеристики и свойства языков программирования. Исследование эволюции объектно-ориентированных языков программирования. Построение эволюционной карты механизмов ООП. Разработка концептуальной модели функционирования пользовательского интерфейса.

    курсовая работа , добавлен 17.11.2014

    Рассмотрение общих сведений и уровней языков программирования. Ознакомление с историей развития, использования языков программирования. Обзор достоинств и недостатков таких языков как Ассемблер, Паскаль, Си, Си++, Фортран, Кобол, Бейсик, SQL, HTML, Java.

    курсовая работа , добавлен 04.11.2014

    Основные концепции языков программирования, механизмы типизации данных. Описание языков программирования и методов трансляции. Конечные автоматы и преобразователи. Общие методы синтаксического анализа. Формальные методы описания языкового перевода.

    курс лекций , добавлен 04.12.2013

    Основы систематизации языков имитационного моделирования, моделирование систем и языки программирования. Особенности использования алгоритмических языков, подходы к их разработке. Анализ характеристик и эффективности языков имитационного моделирования.

    курсовая работа , добавлен 15.03.2012

    Оценка современного этапа развития компьютерных технологий. История развития, классификации, сведения и уровни языков программирования. Обзор современных языков программирования: Си, его разовидности, Паскаль, Фортран, Бейсик - тенденция их развития.

    курсовая работа , добавлен 22.12.2010

    Описание современных языков программирования (Паскаль, Ассемблер, С++, Бейсик, Лого, Форт, Пролог, Рефал и Лекс). Понятие, назначение и составные элементы систем программирования (машинно-ориентированных и машинно-независимых систем программирования).

Программисты и ученые, как правило, пристрастны, когда речь заходит о достоинствах и недостатках различных языков программирования. Сравнив несколько языков, автор попытался получить объективную информацию о Си, Си++, Java, Perl, Python, Rexx и Tcl.

Для сопоставления была использована одна программа, которая предъявляет одинаковый набор требований ко всем языкам. Такой прием сужает область сравнения, но делает ее однородной. Кроме того, для каждого языка было проанализировано несколько отдельных реализаций программы, подготовленных различными программистами. Групповой подход имеет два преимущества. Во-первых, сглаживаются различия между отдельными программистами, которые могут лишить достоверности любые сравнения, основанные на единственном «образце» для каждого языка. Во-вторых, появляется возможность сравнить изменчивость характеристик программ, составленных на разных языках.

В ходе сравнительного исследования сопоставлялись различные аспекты каждого языка, в том числе длина программы, усилия, затраченные на программирование, время выполнения, занимаемое пространство памяти и надежность. Языки сравнивались индивидуально и по группам. Языки сценариев, такие как Perl, Python, Rexx и Tcl чаще интерпретируются, чем компилируются (по крайней мере, на этапе разработки программ), и обычно не требуют определения переменных.

Более традиционные языки программирования - Си, Си++ и Java - чаще компилируются, чем интерпретируются и требуют описания типов переменных. Поскольку многие считают язык Java очень неэффективным, я иногда относил Си и СИ++ к одной группе, а Java к другой.

Диаграммы и статистические методы

В качестве основного инструмента оценки в статье используется блочная диаграмма, показанная на рис. 1. Каждая линия представляет одно подмножество данных, имя которого указано слева. Каждым малым кружком обозначено одно значение данных. Остальная часть диаграммы помогает визуально сравнить два или несколько подмножеств данных. В затененном блоке заключена средняя половина значений, между верхними границами первой четверти (25%) и третьей четверти (75%). «Усы» слева и справа от блока показывают нижние и верхние 10%, соответственно. Жирная точка внутри блока - верхняя граница второй четверти (50%). Символ «M» и разорванная линия вокруг него показывает среднее арифметическое, плюс/минус среднеквадратическую ошибку.

Рис. 1. Время работы программы с набором данных z1000
Исполнение трех программ было завершено безрезультатно по истечении примерно 21 минуты. Разброс отношений «плохих и хороших величин» составляет от 1,5 для Tcl до 27 для Си++. Обратите внимание на логарифмический масштаб оси. Пояснения к данному рисунку относятся также к Рис. 2-7. Более подробное описание дано в разделе «Диаграммы и статистические методы»

Для количественного описания разброса значений в группе было использовано отношение «плохих и хороших величин»: представьте, что данные разделены между верхней и нижней половинами, и отношение «плохих и хороших величин» представляет собой частное от деления среднего значения верхней половины на среднее значение нижней половины. На блочной диаграмме средним считается значение, полученное в результате деления величины у правого края блока на величину у левого края блока. В отличие от такой меры разброса величин, как среднеквадратичное отклонение, отношение «плохих и хороших величин» эффективно исключает резкие выбросы.

Самый важный вывод можно сделать непосредственно из диаграммы. Однако для перепроверки были выполнены статистические тесты. Для сравнения средних значений используется односторонний U-критерий Манна-Уитни (также называемый критерием суммы рангов Уилкоксона). Результат каждого теста - p, величина, характеризующая вероятность того, что наблюдаемая разница между двумя выборками лишь случайна, и что в действительности различия между двумя группами величин отсутствуют или имеют противоположный знак. Обычно само p-значение не приводится, а в тексте статьи указывается «... больше, чем...», если 0 0,10, то «существенных различий нет».

В ряде случаев указаны доверительные интервалы для различий в средних значениях или для различий в логарифмах средних значений - т. е., отношений средних величин. Выбраны открытые уровни доверительности, с бесконечной верхней границей. Доверительные интервалы вычислены методом раскрутки (bootstrap), подробно описанным во многих источниках (см., например, ).

Учитывая опасения относительно достоверности данного исследования, количественные статистические выводы указывают лишь на общие закономерности и не должны рассматриваться как точные факты.

Результаты

Для оценки программ использовались три различных входных файла: z1000, содержащий 1000 непустых случайных телефонных номеров; m1000, содержащий 1000 произвольных случайных телефонных номеров, некоторые из которых могли быть пустыми; и z0, не содержащий телефонных номеров и служащий исключительно для измерения времени загрузки словаря.

Время выполнения программы

Я начал анализ с измерения полного времени выполнения, а затем исследовал отдельно этапы инициализации и поиска.

Полный набор данных z1000. Как показано на рис. 1, время выполнения всех программ за исключением Си++, Java и Rexx, составляет менее 1 мин. Сравнивая данные, можно сделать несколько значимых выводов.

  • Среднее время выполнения программ Tcl незначительно больше, чем Java и даже Си++.
  • Среднее время выполнения как для Python, так и для Perl меньше, чем Rexx и Tcl.
  • Средний показатель Си++ может ввести в заблуждение. Из-за довольно большого разброса между соседними большими и меньшими величинами, среднее значение нестабильно. Критерий Уилкоксона, который учитывает весь набор данных, подтверждает, что среднее время для Си++, как правило, меньше среднего времени для Java (p = 0,18).
  • Среднее время выполнения для Си меньше, чем для Java, Rexx и Tcl, и как правило, меньше чем для Perl и Python.
  • Время выполнения для Tcl и Perl - за исключением двух очень медленных программ - как правило, более стабильно, чем время выполнения программ на других языках.

Не следует придавать особенно большого значения диаграммам для Си и Rexx, построенным всего по нескольким точкам. Время выполнения программ на Rexx может быть снижено примерно в четыре раза, если перекомпилировать интерпретатор Regina для использования хеш-таблиц большего размера; требования к памяти при этом возрастают незначительно. Если объединить языки всего в три группы (одна - Си и СИ++ , вторая - Java, третья - языки сценариев), то программы на Си и Си++ работают быстрее, чем Java (p = 0,074), и как правило, быстрее сценариев (p = 0,15).

Между средним временем выполнения программ на Java и сценариев нет существенной разницы. С вероятностью 80% сценарий будет выполняться в 1,29 раза дольше - а программа на Java по меньшей мере в 1,22 раза дольше - чем программа на Си или Си++. Отношение «плохих и хороших величин» значительно меньше для сценариев (4,1), чем для Java (18) и даже для Си и Си++ (35).

Только этап инициализации, набор данных z0. Затем я измерил время, необходимое для считывания, предварительной обработки и сохранения словаря. Соответствующие времена приведены на рис. 2. Результаты явно свидетельствуют, что Си и Си++ выполняют эту фазу быстрее, чем другие протестированные языки. И вновь, самыми быстрыми языками сценариев оказались Perl и Python. Как выяснилось (с вероятностью 80%) при сравнении укрупненных групп, программа на Java будет выполняться по крайней мере в 1,3 раза дольше, чем программы на Си и Си++, а для выполнения сценария потребуется по крайней мере в 5,5 раз больше времени. Сценарий будет выполняться по крайней мере в 3,2 раза дольше программы на Java.

Рис. 2. Время, затраченное программой только на загрузку и предварительную обработку словаря (набор данных z0). Обратите внимание на логарифмический масштаб оси. Соотношение «плохих и хороших величин» в пределах от 1,3 для Tcl до 7,5 для Python

Только этап поиска. И наконец, я вычел время время этапа загрузки (набор данных z0) из полного времени выполнения (набор данных z1000), чтобы получить время только поискового этапа программы. На рис. 3 показаны соответствующие времена, из которых можно сделать следующие выводы.

  • Очень быстрые программы составлены на всех языках, за исключением Rexx и Tcl, а очень медленные программы встречаются на всех языках.
  • Среднее время выполнения программ на Tcl больше, чем время программ на языках Python, Perl и Си, но меньше, чем на Rexx.
  • Среднее время выполнения программ на Python меньше, чем времена для Rexx и Tcl, и как правило, меньше, чем время выполнения Java (p = 0,13).
  • Среднее время выполнения программ на Perl меньше средних показателей для Rexx, Tcl и Java.
  • Среднее время Си++ существенно отличается от результатов любого другого языка.

Рис. 3. Время, затраченное программой только на поиск, вычисленное как разность между временем работы с набором данных z1000 и набором данных z0. Обратите внимание на логарифмический масштаб оси. Соотношение «плохих и хороших величин» в пределах от 2,9 для Perl до 50 для Си++

Сравнение укрупненных групп свидетельствует об отсутствии серьезных различий между любыми группами. Однако можно с вероятностью 80% утверждать, что разброс времени выполнения сценариев по крайней мере в 2,1 раза меньше, чем у Java, и по крайней мере в 3,4 раза меньше, чем у Си и Си++.

Требования к памяти

На рис. 4 показан общий размер процесса в конце обработки входного файла z1000. Из него можно сделать несколько выводов.

  • Очевидно, что наиболее эффективно память используется в программах групп Си и Си++, а наименее эффективно - в программах группы Java.
  • За исключением Tcl, лишь немногие сценарии потребляют больше памяти, чем худшая половина программ на Си и Си++.
  • Для сценариев Tcl требуется больше памяти, чем для других сценариев.
  • Относительный разброс требований к памяти программ на Python и Perl, как правило меньше, чем программ на Си и в особенности Си++.
  • Некоторые сценарии занимают большие области памяти.
  • При сравнении укрупненных групп можно утверждать с вероятностью 80%, что в среднем программы на Java занимают по крайней мере на 32 Мбайт больше памяти (297%), чем программы на Си и Си++, и по крайней мере на 20 Мбайт больше (98%), чем сценарии. Сценарии занимают по крайней мере на 9 Мбайт больше памяти (85%), чем программы на Си и Си++.

Рис. 4. Объем памяти, необходимый программе, в том числе для размещения интерпретатора или исполняющей системы, собственно программы и всех статических и динамических структур данных. Соотношение «плохих и хороших величин» в пределах от 1,2 для Python до 4,9 для Си++

Из этих данных можно заключить, что требования Java к памяти обычно вдвое выше требований сценариев, а сценарии не обязательно менее эффективно используют память, чем программы, составленные на Си и Си++, хотя и не могут превзойти экономную программу на Си или Си++.

Здравый смысл подсказывает, что алгоритмическим программам свойствен компромисс между временем выполнения и объемом используемой памяти: для увеличения скорости работы обычно нужно выделить программе больше места. В исследованном нами наборе программ это правило действует для всех трех несценарных языков, но для сценарных языков справедливо, скорее, обратное правило: сценарии, использующие больше памяти, как правило, работают медленнее сценариев, занимающих меньше памяти.

Длина программ и число комментариев

На рис. 5 показано число строк исходного файла каждой программы, в которых содержится любая семантическая информация программы: операторы, определения или по крайней мере разделители, такие как закрывающая фигурная скобка. Несценарные файлы обычно вдвое или втрое длиннее сценариев. Даже самые длинные сценарии короче средних несценарных исходных текстов. Вместе с тем, плотность комментариев в сценариях значительно выше (p = 0,020): в несценарных программах в среднем содержится на 22% больше строк с комментариями, чем строк с операторами; для сценариев этот показатель составляет 34%.

Рис. 5. Длина программы: число строк исходного текста без комментариев. Соотношение «плохих и хороших величин» в пределах от 1,3 для Си до 2,1 для Java и 3,7 для Rexx

Надежность программ

При работе с входным файлом z1000 три программы - одна на языке Си, одна на Си++ и одна на Perl - не выдали корректных результатов, поскольку не могли загрузить большой словарь или из-за истечения времени, отведенного на завершение этапа загрузки. Две программы на Java имели почти нулевую надежность и отказали по другим причинам; а одна программа на Rexx выдала много результатов, используя некорректный, только форматирующий сценарий - ее надежность составила 45%.

Отбросив эти явно ошибочные программы - тем самым, были исключены 13% программ на Си и Си++, 8% программ на Java и 5% сценариев - и сравнив остальные по языковым группам, мы обнаружили, что программы на Си и Си++ менее надежны, чем Java и сценарии. Однако эти различия были вызваны лишь несколькими программами с дефектами и потому не могут служить основанием для общих выводов.

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

Затем я сравнивал поведение при работе с входным файлом m1000, в котором могут содержаться телефонные номера без цифр, лишь с тире и наклонными чертами. Такие телефонные номера должны преобразовываться в пустые записи, но программисты склонны забывать о таких требованиях, читая задание. Поэтому на файле m1000 проверяется добротность программы. Большинство программ успешно справились с этой ситуацией, но половина программ Java и четыре сценария - один Tcl и три на языке Python - зависли на первом пустом телефонном номере, после того, как было выдано 10% результатов. Обычно сбой происходил из-за неправильного индекса строки или массива. Среди прочих программ, 15 - одна составленная на Си, пять Си++, четыре Java, две Perl, две Python и одна Rexx - не смогли обработать пустые телефонные номера, но в остальном работали корректно; их надежность составила 98,4%.

В целом, надежность сценариев, по-видимому, не ниже надежности несценарных программ.

Время работы и продуктивность труда

На рис. 6 показано общее время, затраченное на проектирование, составление и тестирование программы, сообщенное авторами сценариев и измеренное для программистов несценарных программ.

Рис. 6. Полное время, затраченное на реализацию программы
Программисты сценарной группы измеряли и сообщали время работы: время языков «несценарной» группы измерялось экспериментатором. Соотношение «плохих и хороших величин» в пределах от 1,5 для Си до 3,2 для Perl. Три величины для Java - рабочее время 40, 49 и 63 час - выходят за границы диаграммы и потому не показаны.

Мы обнаружили, что время составления сценариев с общей медианой 3,1 часа более чем вдвое меньше, чем несценарных программ с общей медианой 10,0 часов, хотя вероятно, различие преувеличено из-за неполной достоверности эксперимента.

К счастью, можно одновременно проверить два фактора, а именно, корректность сообщений о времени, затраченном на составление программ, и равенство квалификации программистов в сценарной и несценарной группах. Оба этих фактора, если они действительно играют роль, должны способствовать снижению времени работы сценарной группы: я предполагаю, что субъективные сообщения будут содержать уменьшенное, а не преувеличенное время работы программы, а в случае появления различий мы ожидали обнаружить более квалифицированных программистов в сценарной группе, поскольку в 1997 и 1998 годах, когда проводилось исследование, программисты Java были менее опытными, чем специалисты по другим языкам. В основу данной проверки положено старое практическое правило, согласно которому число строк исходного текста, выдаваемых программистом в час, не зависит от языка программирования. В нескольких широко применяемых методах оценки трудозатрат - в том числе Cocomo Барри Боэма и таблицах языков программирования для оценки функциональных точек Кейперса Джонса - явно предполагается, что почасовое число строк исходного текста не зависит от языка программирования. На рис. 7 показаны оценки рабочего времени, составленные на основе этого правила. Судя по достоверно известному диапазону продуктивности при работе с Java, все величины, за исключением трех лучших результатов для Tcl и лучших времен для Perl, выглядят правдоподобно.

Рис. 7. Число строк исходного текста, написанных за полный рабочий час. Соотношение «плохих и хороших величин» в пределах от 1,4 для Си до 3,1 для Tcl

Ни одно из медианных различий не имеет явной статистической значимости, хотя отличия Java от Си, Perl, Python и Tcl (0,07

Данное сопоставление придает дополнительную достоверность нашему сравнительному исследованию затрат рабочего времени. Время, сообщенное программистами сценариев, по-видимому, лишь слегка занижено, или точно соответствует действительности. Таким образом, подтверждается двукратное преимущество языков сценариев в затратах рабочего времени. Временные затраты при работе с Java кажутся преувеличенными, поскольку в период проведения исследования Java-программисты были менее опытными, чем другие программисты.

Структура программы

При рассмотрении методов, избранных программистами, работающими с разными исследуемыми языками, обнаруживаются поразительные различия. Большинство программистов в группе сценариев использовали реализованные в языках ассоциативные массивы и сохраняли словарные слова для последующего считывания по числовым кодам. Поисковый алгоритм просто пытается извлечь данные из массива, используя в качестве ключа префиксы возрастающей длины, построенные на основе оставшейся части текущего телефонного номера. Каждое совпадение дает новое частичное решение, обработка которого будет завершена позднее.

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

Более изощренный подход состоит в использовании 10-арного дерева, каждый узел которого представляет определенную цифру, а узлы на высоте n представляют n-ный символ слова. Слово хранится в узле, если путь от корня к данному узлу представляет числовой шифр слова. Это решение - самое эффективное, но для построения и прохождения дерева требуется сравнительно большое число операторов. В Java многочисленность результирующих объектов приводит к большому расходу памяти из-за необходимости выделять чрезвычайно крупные области для хранения каждого объекта в текущих реализациях среды исполнения Java-программ.

В сценариях содержится меньше операторов, чем в несценарных программах, поскольку основная часть поисковых операций выполняется с помощью внутренних алгоритмов хеширования ассоциативных массивов. В отличие от них, в несценарных программах приходится явно задавать элементарные шаги поискового процесса. Эти различия еще более усугубляются усилиями - или их отсутствием - на построение структур данных и описание переменных.

Хотя хеш-таблицы реализованы в библиотеках классов как для Java, так и для Си++, ни один из программистов, работающих с несценарными языками не воспользовался ими, предпочитая строить дерево вручную. И наоборот, авторы сценариев с готовностью применяют встроенные в их языки хеш-таблицы.

Важнейшие выводы

Сравнительный анализ 80 реализаций программы кодирования телефонных номеров на семи различных языках принес следующие важнейшие результаты.

  • Проектирование и составление программ на языках Perl, Python, Rexx и Tcl занимает не более половины времени, необходимого для программирования на Си, Си++ и Java - а длина исходного текста вдвое меньше.
  • Явных различий в надежности между программами различных языковых групп не обнаружено.
  • Типичный сценарий занимает примерно вдвое больше памяти, чем программа на Си или Си++. Программы на Java занимают втрое и вчетверо больше памяти, чем программы на Си и Си++.
  • Программы на Си и Си++ выполняют инициализацию программы преобразования телефонных номеров, которая заключается в считывании словарного файла размером в 1 Мбайт и построении 70-килобайтной внутренней структуры данных, в три или четыре раза быстрее, чем программы на Java и примерно в пять или десять раз быстрее, чем сценарии.
  • На основном этапе программы преобразования телефонных номеров ведется поиск во внутренней структуре данных, и программы на Си и Си++ работали всего примерно вдвое быстрее Java. Сценарии, как правило, работают быстрее программ на Java.
  • Среди сценарных языков Perl и Python выполняли оба этапа быстрее, чем Tcl.
  • Разброс любых исследованных параметров программ, возникший вследствие различий между программистами, работающими на одном языке - отраженный отношениями «плохих и хороших величин» - в среднем такой же или больше разброс характеристик, вызванного различиями языков.

Учитывая многочисленность реализаций и широкий круг программистов, результаты данного исследования, при критическом к ним отношении, вероятно, достаточно надежны, несмотря на отмеченные факторы, снижающие достоверность. Однако результаты следует считать корректными только для проблемы преобразования телефонных номеров; обобщение на различные области применения будет рискованным. Например, вызывает сомнения, что относительные результаты группы сценарных языков полностью подтвердятся при решении других проблем.

Несмотря на эти недостатки, прямое сопоставление различных языков программирования может принести полезную информацию. Например, можно сделать вывод, что издержки Java при работе с памятью по-прежнему огромны в сравнении с Си и Си++, однако время выполнения программ стало вполне приемлемым. Языки сценариев превратились в разумную альтернативу Си и Си++, даже для задач, связанных с обширными вычислениями и обработкой крупных массивов данных. Их относительное время выполнения и требования к памяти часто приемлемы, а программировать на них гораздо быстрее, по крайней мере, при составлении небольших программ.

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

Лутц Прехельт ( [email protected]) - руководитель службы контроля качества компании abaXX Technology (Штуттгарт, Германия).

Литература

1. E. Bradley and R. Tibishirani, «An Introduction to the Bootstrap,» Monographs on Statistics and Applied Probability 57, Chapman and Hall, New York, 1993
2. L. Prechelt, An Empirical Comparison of C, C++, Java, Perl, Python, Rexx and Tcl for Search/String-Processing Program, Tech Report 2000-5, Fakultat fur Informattik , Universitat Karlsruhe, Germany, Mar. 2000.
3. B.W. Boehm, Software Engineering Economics, Prentice Hall, Englewood Cliffs, N.J., 1981
4. C. Jones, Software Productivity Research , Programming Languages Table, Version 7, 1996.

An Empirical Comparison of Seven Programming Languages, Lutz Prechelt, IEEE Computer, October 2000, pp. 23-29. Copyright IEEE CS, Reprinted with permission. All rights reserved.

Достоверность сравнения

Любое сравнение языков программирования, основанное на сопоставлении образцовых программ, достоверно лишь в той мере, в какой могут считаться одинаковыми способности программистов, работающих с этими языками. В нашем случае, должен был быть сопоставимым лишь общий уровень программ, а не их индивидуальные качества. Ряд факторов мог отрицательно влиять на сопоставимость 80 программ, проанализированных в ходе данного исследования.

Программы получены из двух различных источников. Программы на Java, Си и Си++ были составлены в 1997 и 1998 годах во время контролируемого эксперимента, в котором участвовали студенты старших курсов факультета вычислительной техники ( L. Prechelt and B. Unger, A Controlled Experiment on the Effects of PSP Trimming: Detailed Description and Evaluation, Tech Report 1/1999, Fakultat fur Informattik, Universitat Karlsruhe, Germany, Mar. 1999). Программы на Perl, Python, Rexx и Tcl были составлены в различных условиях добровольцами, которые откликнулись на приглашение, опубликованное в нескольких конференциях. Поэтому авторы имели разные уровни подготовки и опыт.

Квалификация программистов

Вероятно, что публичный призыв к сотрудничеству может привлечь только весьма компетентных программистов, поэтому сценарные программы составлялись в целом более квалифицированными специалистами, чем программы на несценарных языках. Однако два обстоятельства позволяют предположить, что данное противоречие не внесло серьезных ошибок в результаты исследования. Во-первых, за некоторыми исключениями, студенты - авторы несценарных программ - достаточно опытны и умелы. Во-вторых, значительная часть авторов сценариев сообщили, что лишь начинают работать с соответствующими языками или не имеют основательной программной подготовки. Среди них были конструктор сверхбольших микросхем, системный администратор и социолог.

В несценарной группе программисты на Java имели меньший опыт работы со своим языком, чем программисты на Си и Си++, поскольку в 1997 и 1998 годах Java был еще новым языком. В сценарной группе программисты на Perl имели более высокую квалификацию, чем другие участники эксперимента; по-видимому, язык Perl привлекает особенно талантливых программистов - по крайней мере, таково мое личное впечатление.

Точность измерения времени работы

Мы точно знаем время программирования в условиях контролируемого эксперимента с несценарными языками, однако ничто не мешало авторам сценариев занизить время, потраченное ими на составление программ. Хуже того, некоторые из авторов, очевидно, приступили к работе спустя много дней после того, как ознакомились с требованиями, предъявляемыми к программам. Один программист сообщил, что начал составлять программу через две недели после прочтения объявления «... в это время подсознательно я мог уже работать над решением.»

Однако практика показывает, что в среднем сроки работы над сценариями также верны: данные для всех языков вполне соответствуют общеизвестной инженерной истине, что «число строк исходного текста, написанное за один час, не зависит от языка». К нашему удовлетворению, те же данные подтверждают, что квалификация авторов сценариев не выше, чем программистов другой группы.

Различие задач и условий работы

Главным требованием к несценарной группе была правильность программы; приемный контроль подразумевал высокую надежность и по меньшей мере некоторую степень эффективности.

К сценарной группе наряду с главным критерием корректности предъявлялись восемь дополнительных качественных требований. Вместо приемного контроля несценарной группы авторам сценариев были предоставлены входные и выходные данные z1000 для собственного тестирования. В обоих случаях различия могут дать преимущество сценарной группе.

Выводы

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