Программа

Прежде чем писать программы, нам очень желательно сначала понять, что вообще такое программа.

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

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

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

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

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

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

Например, можно условно представить так:

  1. если горит только первая лампочка, а остальные не горят — это одна команда;
  2. если горит только вторая лампочка, а остальные не горят — это уже другая команда;
  3. если горят первая и вторая лампочки одновременно — это уже третья команда;
  4. и так далее.

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

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

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

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

Возможно, у вас здесь возникает вопрос: а как, собственно, процессор понимает, как реагировать? Вот подали мы ему определённый сигнал — а что дальше? А всё дело в том, что это уже заложено физически. То есть на уровне железа инженеры заранее устроили процессор так, чтобы на одни комбинации сигналов он реагировал одним образом, а на другие — другим.

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

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

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

Например, если очень грубо представить простую программу, которая складывает три числа, она могла бы выглядеть примерно так:

0001 00000101
0010 00000011
0010 00000010
0011 00000000

Здесь, если говорить совсем условно, первая команда могла бы означать: "возьми число 5". Вторая — "прибавь 3". Третья — "прибавь 2". А последняя — "сохрани или выведи результат". То есть человеку приходилось бы не просто думать о самой задаче, но ещё и буквально передавать машине команды на её собственном языке.

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

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

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

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

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

А высокоуровневые языки устроены уже гораздо ближе к человеческому способу мышления. На них мы описываем не то, какие именно сигналы должны пройти внутри процессора, а то, что именно хотим получить: сложить числа, проверить условие, повторить действие несколько раз, обработать текст, создать объект и так далее. Всё остальное специальные инструменты берут на себя и уже сами переводят наши инструкции в форму, понятную машине. К таким языкам относятся, например, Python, Java, JavaScript и многие другие. Поэтому высокоуровневые языки обычно намного удобнее для обучения и повседневной разработки. Они позволяют сосредоточиться на логике программы, а не держать в голове каждую деталь того, как именно команда будет выглядеть на уровне битов.

Как высокоуровневый язык превращается в действия компьютера

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

Например, простая запись арифметического выражения на Python может выглядеть примерно так:

5 + 3

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

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

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

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

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

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

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

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

Практическая работа. Что такое программа

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

Что такое программа

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

13

Что такое программа?

23

Почему человеку неудобно писать программы напрямую в машинном коде?

33

Зачем нужны языки программирования вроде Python?

Обсуждение урока

0
Комментарии видны всем. Чтобы участвовать в обсуждении, войдите или зарегистрируйтесь.
Модерация сообщества

Пожаловаться на комментарий

Расскажите модераторам, что именно требует внимания.