Поведение программ
Одна и та же программа может вести себя по-разному — веб-сервер слушает порт 8080 или 443, лог пишется в файл или в консоль, интерфейс — светлый или тёмный. Часть этих правил задаётся до запуска (файлы конфигурации, переменные среды), часть — в момент запуска (аргументы командной строки), часть — во время работы (кнопки в настройках). Эта статья связывает эти уровни с процессами, потоками и зависимостями.
Запуск и роль ОС — Что такое программа? и Взаимодействие с ОС.
Установка версий и пересборка после изменений — статья 114.
Командная строка и флаги — Терминал.
Поведение системы
Конфигурация и параметры
Программам нужен набор правил: настройки в интерфейсе, параметры при запуске и конфигурационные файлы на диске. Все они описывают одно и то же — как программа должна работать в данной среде, без переписывания исходного кода.
Play ITЗагрузка интерактивного демо…

★ Конфигурация – файлы (например, формата .config или .json), или переменные среды, определяющие поведение программы. Конфигурация состоит из конфигурационных единиц.
★ Конфигурационная единица — минимальный элемент настройки программы, задающий конкретное значение параметра, определяющего её поведение. Это атом конфигурации: одна "настройка" — одна единица.
Конфигурационные единицы существуют в разных формах, но всегда состоят из ключа и значения.
Форматы представления
| Формат | Структура | Пример конфигурационной единицы |
|---|---|---|
| INI | ключ=значение | port=8080 |
| JSON | "ключ": значение | "log_level": "debug" |
| YAML | ключ: значение | theme: dark |
| XML | <ключ>значение</ключ> | <max_connections>100</max_connections> |
| Переменная среды | ИМЯ=значение | DATABASE_URL=postgres://user:pass@localhost/db |
| Флаг командной строки | --ключ=значение или -k значение | --verbose, -p 3000 |
Типы значений конфигурационных единиц
- Булевы —
true/false,on/off,1/0
—enable_tls=true,debug_mode=false - Числовые: целые (
max_workers=4), вещественные (timeout_sec=2.5) - Строковые: пути (
data_dir="/var/lib/app"), имена (app_name="InvoiceGenerator") - Списки и массивы:
allowed_origins:
- "https://example.com"
- "https://admin.example.com"
- Вложенные структуры (объекты):
"database": {
"host": "localhost",
"port": 5432,
"pool_size": 10
}
Особенности конфигурационных единиц
-
Иерархия: единицы могут группироваться в секции или вложенные объекты для улучшения читаемости и логической группировки.
-
Приоритет источников: одна и та же единица может быть задана в нескольких местах. Обычно действует порядок приоритета (от самого сильного к слабому):
- Флаги командной строки,
- Переменные среды,
- Файл конфигурации (
config.json), - Значение по умолчанию (встроено в код).
Например,--port=9000переопределитport: 8080вconfig.yaml.
-
Валидация при загрузке: программа проверяет тип и допустимость значения.
port="abc"вызовет ошибку, так как порт должен быть целым числом от 1 до 65535. -
Изменяемость во время выполнения: некоторые программы поддерживают горячую перезагрузку конфигурации — чтение обновлённого файла без перезапуска (например, Nginx:
nginx -s reload).
Конфигурационная единица — это её техническое воплощение. Даже когда пользователь ставит галочку "Запускать при старте системы" в настройках приложения, где-то в settings.json появляется запись: "autostart": true.
Есть ещё понятие конфигурации как набора комплектующих – компонентов компьютера, но это значение мы не рассматриваем. Для нас конфигурация сейчас это набор правил, настроек или параметров, которые определяют поведение программы. Она позволяет адаптировать программное обеспечение под конкретные задачи без необходимости изменения его исходного кода.
Конфигурационные файлы (например, .config, .json, .ini, .yaml) содержат пары "ключ — значение", которые программа считывает при запуске (и иногда перечитывает без перезапуска). Пример для веб-сервера Nginx:
server {
listen 8080;
access_log /var/log/nginx/access.log;
}
Здесь listen и access_log — конфигурационные единицы: они задают порт и путь к логу без изменения исходного кода сервера.
Главное преимущество конфигурации - возможность легко изменить поведение программы без пересборки или переписывания кода.
Например, если нужно перевести интерфейс программы на другой язык, достаточно изменить значение соответствующего параметра в конфигурационном файле.
★ Настройка программы – формирование конкретного варианта программы под свои задачи. Настройка — это процесс адаптации под конкретные требования, включая изменение языка интерфейса, выбор темы оформления, настройку производительности, определение путей к файлам. Часто выводятся в графический интерфейс, чтобы пользователи могли легко изменять их без углубления в технические детали, лишь выбирая значения в выпадающих списках, расставляя флаги (галочки).
★ Параметры – аргументы командной строки (дополнительные выражения к команде), к примеру, --debug. Они позволяют управлять поведением командной строки непосредственно при запуске. Параметры особенно полезны для системных администраторов и разработчиков, но также используется и ещё одно понятие. Иногда под параметрами подразумевают какой-то флаг, аргумент, ключ, который что-то определяет. Допустим, включение или выключение какого-то свойства или поведения программы. Их можно назвать всеми этими значениями - флаг, параметр, галочка. Именно поэтому часто разделы настроек называются "Параметры" - потому что это какой-то набор аргументов, где пользователь может расставить соответствующие значения.
И всё это - настройка, параметр - есть конфигурация - определение поведения.
Без конфигурации пришлось бы переписывать код для каждого изменения, допустим, смена языка интерфейса. А благодаря конфигурации всё хранится в легко редактируемом файле, зачастую доступном через интерфейс настроек.
★ Параметры системы — значения, задающие глобальное состояние операционной системы или среды выполнения программ. Они влияют на поведение множества компонентов сразу — ядра, служб, приложений, командной строки.
Параметры системы делятся на категории по области действия и способу задания.
1. Параметры ядра (kernel parameters)
Конфигурационные настройки, управляющие работой ядра ОС. В Linux они доступны через виртуальную файловую систему procfs и sysfs.
Примеры:
vm.swappiness=10— насколько активно система будет использовать swap при нехватке RAM,net.core.somaxconn=1024— максимальное количество ожидающих подключений для сокета,kernel.panic=10— через сколько секунд перезагружать систему при критической ошибке.
Изменяются через:
/etc/sysctl.conf(постоянно),sysctl -w vm.swappiness=10(временно, до перезагрузки).
2. Системные политики и ограничения
Параметры, задающие рамки работы пользователей и процессов.
Примеры:
ulimit -n 4096— максимальное количество открытых файловых дескрипторов для процесса,/etc/security/limits.conf— лимиты на количество процессов, объём памяти, приоритет,- SELinux/AppArmor политики — разрешения на доступ к файлам, сетевым портам, системным вызовам.
3. Параметры времени и локализации
timedatectl set-timezone Europe/Moscow— часовой пояс,localectl set-locale LANG=ru_RU.UTF-8— язык и кодировка,LC_TIME,LC_MONETARY— формат даты, валюты для конкретного сеанса.
4. Параметры сетевой подсистемы
ip route add default via 192.168.1.1— шлюз по умолчанию,iptables -A INPUT -p tcp --dport 22 -j ACCEPT— правило фаервола,/etc/resolv.conf— DNS-серверы.
5. Параметры виртуальной машины (для Java, .NET)
-Xmx2g— максимальный объём кучи для JVM,-XX:+UseG1GC— выбор сборщика мусора,COMPlus_GCHeapHardLimit=0x80000000— лимит памяти для .NET GC.
Особенности параметров системы:
- Они действуют глобально или на уровне пользователя/процесса,
- Часто требуют прав администратора для изменения,
- Имеют приоритет над настройками отдельных программ (например, если система запрещает открытие портов < 1024, приложение не сможет запустить веб-сервер на порту 80 без
sudo), - Изменения могут требовать перезагрузки или перезапуска служб.
Параметры системы — это "правила дорожного движения" для всего программного стека. Они не определяют, что делает программа, но строго ограничивают, как она может это делать.
Поведение программы
★ Поведение программы — совокупность действий, которые программа выполняет в ответ на входные данные, команды, события или изменения состояния среды. Поведение — это то, как программа работает, а не что она делает в общих чертах.
Поведение определяется тремя основными факторами:
1. Исходный код
Алгоритмы, условия, циклы, вызовы функций — всё это задаёт логику. Например:
- "Если пользователь ввёл пароль короче 8 символов — показать ошибку",
- "При получении HTTP-запроса GET
/api/users— вернуть JSON со списком пользователей".
2. Конфигурация
Настройки влияют на варианты поведения без изменения кода:
log_level=debug→ программа записывает подробные отладочные сообщения,cache_enabled=false→ каждый запрос идёт напрямую к базе данных, без кэширования,ui_theme=dark→ интерфейс отрисовывается в тёмных тонах.
3. Состояние среды
Внешние условия, от которых зависит реакция:
- Наличие файла
config.local.yaml→ программа загружает локальные переопределения, - Сетевая задержка
>5 сек → срабатывает таймаут и повторная попытка, - ОЗУ
<512 МБ → программа отключает необязательные функции для экономии памяти.
Примеры поведения
| Ситуация | Поведение |
|---|---|
| Пользователь нажимает "Сохранить" | — Проверяется валидность формы, — Данные сериализуются в JSON, — Отправляется POST-запрос на /save, — При успехе — показывается зелёная нотификация, — При ошибке — красная и лог в консоль. |
| Сервер получает запрос к несуществующему URL | — Возвращается HTTP 404, — В лог пишется: WARN: route /xyz not found, — Пользователю отдаётся страница "404 — Страница не найдена". |
| Закончилось место на диске | — Программа прекращает запись логов, — Отправляет уведомление администратору, — Переходит в "режим только чтение". |
Поведение можно описать формально — через спецификации (например, OpenAPI для API), сценарии использования (use cases), конечные автоматы (состояния: idle → loading → success/error).
Хорошо спроектированная программа стремится к детерминизму: при одинаковых входах, конфигурации и среде — один и тот же результат. Исключения — сеть, время, случайные числа, параллельные потоки; их учитывают отдельно при тестировании.
Пересборка
★ Пересборка — процесс повторного запуска инструментов сборки (компилятора, линковщика, упаковщика) для получения нового исполняемого файла или артефакта на основе изменённого исходного кода или конфигурации.
Пересборка происходит после внесения изменений, которые влияют на итоговый результат:
- изменение
.c,.java,.pyфайлов, - обновление зависимостей (новая версия библиотеки),
- изменение параметров сборки (режим отладки → релиз),
- модификация ресурсов (картинки, строки локализации).
Этапы пересборки (на примере C++)
- Предобработка: подстановка
#include, развертывание#define. - Компиляция: каждый
.cpp→.o(объектный файл с машинным кодом). - Линковка: объединение
.o-файлов и библиотек →program.exe. - Постобработка — минификация, обфускация, добавление цифровой подписи.
Современные системы сборки оптимизируют пересборку:
- Инкрементальная сборка — перекомпилируются только изменившиеся файлы и их зависимости (
make,MSBuild), - Кэширование артефактов — повторное использование уже собранных объектов (
ccache,sccache), - Параллельная сборка: запуск нескольких компиляторов одновременно (
make -j8).
Примеры пересборки в разных средах
| Среда | Команда | Что делает |
|---|---|---|
| Python (Nuitka) | nuitka --standalone app.py | Пересобирает app.py в автономный .exe |
| Java (Maven) | mvn clean compile | Очищает target/, компилирует .java → .class |
| .NET | dotnet build --configuration Release | Собирает проект в режиме оптимизации |
| Web (Webpack) | npm run build | Пересобирает JS/CSS/HTML в dist/ |
| Linux (make) | make && sudo make install | Пересобирает и устанавливает программу из исходников |
Пересборка — управляемый процесс, который гарантирует, что итоговый артефакт соответствует текущему состоянию кодовой базы. Без пересборки изменения в коде останутся "на бумаге".
★ Переписывание кода — процесс полной или частичной замены исходного кода программы с сохранением её внешнего поведения или с целенаправленным изменением архитектуры, стиля, производительности.
Переписывание отличается от обычного редактирования масштабом и целью. Это "перестроил фундамент".
Виды переписывания
| Тип | Цель | Пример |
|---|---|---|
| Рефакторинг | Улучшение структуры кода без изменения функциональности | Замена глобальных переменных на внедрение зависимостей; выделение повторяющегося кода в функцию. |
| Миграция на другой язык | Получение преимуществ новой платформы | Python-скрипт → переписан на Rust для скорости и отсутствия GIL. |
| Смена архитектуры | Перевод с монолита на микросервисы, или наоборот | Веб-приложение на PHP → фронтенд на React + бэкенд на Go. |
| Обновление устаревших решений | Замена deprecated API, библиотек, подходов | jQuery → Vanilla JS + modern fetch API; Python 2 → Python 3. |
| Оптимизация производительности | Снижение времени отклика, потребления памяти | Переписывание критического цикла на C и вызов из Python через ctypes. |
Причины переписывания
- Технический долг — код стал нечитаемым, не тестируемым, хрупким.
- Ограничения языка/платформы — отсутствие нужных библиотек, плохая производительность, отсутствие поддержки.
- Изменение требований — нужно масштабирование, отказоустойчивость, поддержка новых ОС.
- Командные предпочтения: новая команда лучше знает другой стек технологий.
- Юридические аспекты: отказ от проприетарных компонентов в пользу open source.
Особенности процесса
- Параллельная разработка: новая версия создаётся отдельно, пока старая продолжает работать (стратегия * strangler fig pattern*).
- Постепенный перевод: часть функций переносится постепенно, через API-адаптеры.
- Тестирование как основа — автоматические тесты (unit, integration) позволяют убедиться, что поведение не изменилось.
- Документирование изменений — фиксация причин, архитектурных решений, откат-планов.
Переписывание — серьёзное решение. Оно требует ресурсов, времени и чёткого понимания целей. Но иногда это единственный способ вывести проект на новый уровень качества и возможностей.
Переменные среды
Конфигурация может быть также представлена переменными среды, которые задают глобальные настройки для ОС или конкретных программ. Например, переменная LANG в Linux определяет язык системы, а %APPDATA% в Windows указывает путь к данным пользовательских приложений.
★ Переменная среды — пара "имя–значение" в ОС — пути, язык, секреты для приложений. В Windows часть переменных хранится в реестре и в диалоге "Переменные среды"; в Linux — в профилях shell и /etc/environment.
Примеры в Windows:
| Имя переменной | Суть и назначение |
|---|---|
%APPDATA% | Настройки программ текущего пользователя. Пример: C:\Users\Admin\AppData |
%WINDIR% | Место установленной Windows. Пример: C:\Windows |
%PROGRAMFILES% | Стандартная папка установки приложений. Пример: C:\Program Files |
Примеры в Linux:
| Имя переменной | Суть и назначение |
|---|---|
USER | Имя текущего пользователя |
HOME | Домашний каталог |
LANG | Локаль и язык интерфейса |
В проводнике Windows %APPDATA% в адресной строке подставляет значение переменной. Дочерний процесс при запуске получает копию переменных среды родителя.
Зависимости проекта
Программа редко работает в одиночку — нужны библиотеки, runtime ОС, иногда фреймворк. Список фиксируют в файлах зависимостей; менеджер пакетов скачивает совместимые версии.
Пример requirements.txt (Python):
requests==2.31.0
pydantic>=2.0,<3
Установка: pip install -r requirements.txt.
Пример — запуск python
Когда вы вводите в терминале:
python script.py
Система выполняет следующие шаги:
- Поиск исполняемого файла — оболочка (например,
bash) обращается к переменнойPATH— это список каталогов, разделённых двоеточием (:в Linux/macOS) или точкой с запятой (;в Windows).
ПримерPATHв Linux:
/usr/local/bin:/usr/bin:/bin:/home/user/.local/bin
Оболочка ищет файл с именем python поочерёдно в каждом из этих каталогов.
-
Нахождение интерпретатора: допустим,
pythonнайден в/usr/bin/python3.11. Это символическая ссылка на реальный исполняемый файл. -
Запуск процесса: система создаёт новый процесс, загружает
python3.11, передаёт ему аргументы (script.py), и копирует текущие переменные среды в память нового процесса. -
Использование переменных внутри Python:
Сам интерпретатор и скрипты могут читать переменные:
import os
db_url = os.getenv("DATABASE_URL", "sqlite:///default.db")
debug = os.getenv("DEBUG", "false").lower() == "true"
Пример запуска с переопределением:
DEBUG=true DATABASE_URL=postgres://user:pass@localhost/app python script.py
Распространённые переменные, влияющие на Python
| Переменная | Назначение | Пример значения |
|---|---|---|
PYTHONPATH | Дополнительные пути для поиска модулей | /opt/mylib:/home/user/project/utils |
VIRTUAL_ENV | Путь к активной виртуальной среде | /home/user/venv |
PYTHONIOENCODING | Кодировка stdin/stdout/stderr | utf-8 |
http_proxy / https_proxy | Прокси-серверы для сетевых запросов | http://proxy.corp:3128 |
TZ | Часовой пояс (если не задан в os.environ) | Europe/Moscow |
Как задать переменные
- Временно (на сессию):
export LANG=ru_RU.UTF-8
- Для одной команды:
DEBUG=1 python app.py
- Постоянно:
— В~/.bashrc,~/.profile,/etc/environment,
— В Windows — через "Система → Дополнительные параметры → Переменные среды".
Переменные среды — стандартный, кроссплатформенный способ конфигурирования поведения программ без изменения исходного кода и без правки файлов конфигурации. Они особенно важны в контейнерах (Docker), где каждый параметр часто передаётся через -e KEY=VALUE.
Библиотеки и фреймворки
Представим, что перед вами высококвалифицированный специалист, который решит вашу задачу — это и есть программа. Ему нужна стройплощадка (фреймворк) и готовые ресурсы (библиотеки). По чертежу (исходному коду) специалист собирает результат; если не хватает библиотеки или версии runtime, запуск завершится ошибкой — типичный случай "установите .NET 8" или pip install requests.
Библиотеки — наборы уже написанного кода для узких задач — HTTP-запросы, работа с изображениями, математика. Вместо реализации с нуля подключают пакет и вызывают его API. Языковые экосистемы и типичные библиотеки — в Основные языки; веб-стек клиент/сервер — в Frontend и backend.
Типы библиотек
| Тип | Описание | Примеры |
|---|---|---|
| Стандартная библиотека | Входит в поставку языка или ОС | stdlib в Python, java.util в Java, libc в C |
| Системная библиотека | Часть ОС, обеспечивает доступ к её сервисам | glibc (Linux), Kernel32.dll (Windows), CoreFoundation (macOS) |
| Сторонняя библиотека | Создана сообществом или компанией, подключается отдельно | requests (Python), lodash (JS), OpenSSL (C) |
| Статическая библиотека | Код копируется в исполняемый файл на этапе сборки | .a (Linux), .lib (Windows) |
| Динамическая библиотека | Загружается в память во время выполнения | .so (Linux), .dll (Windows), .dylib (macOS) |
Примеры библиотек и их назначение
| Библиотека | Язык/Платформа | Функционал |
|---|---|---|
requests | Python | Упрощённая отправка HTTP-запросов: r = requests.get("https://api.example.com") |
NumPy | Python | Работа с многомерными массивами, математические операции на высокой скорости |
React | JavaScript | UI-библиотека: компоненты и виртуальный DOM (часто с мета-фреймворками вроде Next.js) |
OpenCV | C++/Python | Компьютерное зрение: распознавание лиц, обработка изображений |
fmt | C++ | Безопасное форматирование строк: fmt::format("Hello, {}!", name) |
log4j | Java | Гибкое логирование: уровни (DEBUG, INFO), вывод в файл/сеть/консоль |
Особенности библиотек
- Чёткий контракт интерфейса — библиотека предоставляет публичный API — функции, классы, константы. Всё остальное скрыто (инкапсуляция).
- Версионирование: каждая библиотека имеет номер версии (часто по SemVer), чтобы отслеживать совместимость.
- Зависимости: библиотека сама может использовать другие библиотеки (транзитивные зависимости).
- Лицензирование: важно учитывать при коммерческом использовании (MIT, Apache 2.0 — разрешают; GPL — требуют открытия кода).
- Производительность: многие библиотеки написаны на низкоуровневых языках (C/C++) и предоставляют обёртки для высокоуровневых (Python, JS).
Системные библиотеки — это компоненты, которые обеспечивают взаимодействие программы с операционной системой, предоставляя доступ к базовым функциям, таким как работа с файловой системой, управление памятью или сетевые подключения.

Фреймворки — это всегда набор инструментов, шаблонов и правил, которые помогают разработчикам создавать приложения быстрее и эффективнее. Они представляют собой базовую структуру, в которой предстоит работать. Это может быть как набор библиотек и утилит для разработки, так и подход к разработке (алгоритмы, порядок и принципы).
★ Фреймворк — комплексная платформа, предоставляющая каркас для разработки приложений. Фреймворк определяет архитектуру, правила взаимодействия компонентов и часто включает в себя библиотеки, инструменты и шаблоны.
В отличие от библиотеки, вы вызываете библиотеку, а фреймворк вызывает вас (Inversion of Control — инверсия управления).
Ключевые признаки фреймворка
- Каркас приложения — шаблон структуры проекта (папки
models/,views/,controllers/), - Жизненный цикл — фреймворк управляет запуском, обработкой запросов, завершением,
- Встроенные компоненты — маршрутизация, ORM, система шаблонов, аутентификация,
- Расширяемость через хуки и плагины: точки подключения собственной логики.
Примеры фреймворков
| Фреймворк | Язык | Назначение | Особенности |
|---|---|---|---|
| Django | Python | Веб-приложения "из коробки" | "Batteries included": админка, ORM, миграции, аутентификация — всё встроено. |
| Spring Boot | Java | Корпоративные сервисы | Автоконфигурация, внедрение зависимостей, интеграция с БД, очередями, облаками. |
| .NET MAUI | C# | Кроссплатформенные мобильные и десктопные приложения | Единый код для Windows, macOS, iOS, Android. |
| Unity | C# | Разработка игр и симуляций | Графический редактор сцен, физический движок, поддержка 2D/3D, ассет-стор. |
| TensorFlow/Keras | Python | Машинное обучение | Граф вычислений, автоматическое дифференцирование, GPU-ускорение. |
| Electron | JavaScript | Десктопные приложения на веб-технологиях | Chromium + Node.js — позволяет писать приложения как веб-сайты. |
Особенности фреймворков
- Ограничение свободы выбора: фреймворк диктует, как писать код. Зато обеспечивает единообразие и предсказуемость.
- Высокая производительность "из коробки" — оптимизации уже встроены (кеширование, пул соединений, асинхронность).
- Большое сообщество и экосистема — документация, курсы, сторонние расширения, готовые решения (boilerplates).
- Сложность входа: требуется изучить не только язык, но и правила фреймворка.
- Риск vendor lock-in: переход на другой стек может потребовать полного переписывания.

Менеджеры пакетов: npm (Node.js), pip (Python), Maven/Gradle (Java), NuGet (.NET), Composer (PHP).
В проекте приложения создаётся файл, который описывает все необходимые зависимости. Это позволяет другим разработчикам воспроизвести среду разработки или развернуть приложение на другом компьютере. Менеджеры пакетов также следят за совместимостью версий зависимостей, что снижает риск конфликтов между компонентами.
Вычисление
★ Вычисление – процесс получения входных данных (допустим, чисел 2 и 3), применения операторов (+, -, * или /), и возвращения результата – допустим, 5 после операции 2+3.

Таким образом, если мы разберем "2 + 3 = 5", мы получим:
- 2 и 3 – операнды;
-
-
- оператор;
-
- 5 – возвращаемый результат.
★ Слово "возвращать" (англ. return) встречается в программировании очень часто, поэтому важно привыкнуть. Это как отправить задачу с исходными данными специалистами, чтобы он вам вернул результат.

★ Возвращение — завершающая фаза выполнения функции или метода, при которой результат её работы передаётся вызывающей стороне. Это передача управления и данных обратно по стеку вызовов.
Каждая функция в программе — как специалист, которому поручили задачу. Он берёт входные данные, выполняет действия, и возвращает результат. Без возврата работа остаётся "внутри" — она не влияет на остальную систему.
Как работает возврат
- Функция получает аргументы (входные данные),
- Выполняет последовательность инструкций,
- В определённый момент достигает оператора
return, - Система:
- сохраняет значение после
return, - освобождает локальную память функции (стековый фрейм),
- передаёт управление обратно в точку вызова,
- подставляет возвращённое значение на место вызова функции.
- сохраняет значение после
Пример на Python:
def add(a, b):
result = a + b
return result # ← возврат значения
x = add(2, 3) # после возврата x получает значение 5
Чем возврат отличается от обычного выполнения
| Аспект | Обычное выполнение | Возврат |
|---|---|---|
| Цель | Выполнение последовательности действий | Передача результата и выход из функции |
| Место в коде | Любая строка внутри тела | Только оператор return (или неявный возврат None/undefined) |
| Побочные эффекты | Может изменять глобальное состояние, писать в файл, отправлять запрос | Не обязан иметь побочные эффекты; чистые функции возвращают только результат |
| Контроль потока | Продолжение выполнения следующей инструкции | Немедленное прекращение работы функции, переход к вызывающему коду |
| Множественные точки выхода | Одно выполнение — один линейный путь (без ветвлений) | Функция может иметь несколько return в разных ветках (if/else) |
Особые случаи
-
Неявный возврат:
В Python функция безreturnвозвращаетNone.
В JavaScript —undefined.
Это всё равно возврат, просто со значением по умолчанию. -
Возврат без значения:
В языках вроде C# или Java метод с типомvoidне возвращает данные, но всё равно выполняет возврат управления:
void Log(string msg) {
Console.WriteLine(msg);
return; // необязательно, но допустимо
}
- Ранний возврат — распространённая техника:
def process_user(data):
if not data:
return False # сразу выходим, если данных нет
# ... остальная логика
Возврат — это интерфейс функции. Он определяет, что функция даёт внешнему миру. Хорошо спроектированный возврат делает код предсказуемым, тестируемым и композируемым.
Задачи и многозадачность
Отличие программы на диске, процесса в RAM и потока — с диаграммой — в Что такое программа?.
Ниже — примеры процессов и потоков в приложениях.
Компьютеры делают много дел "одновременно". На одном ядре в каждый момент выполняется одна машинная инструкция, но процессор миллиарды раз в секунду перебирает инструкции разных программ. Планировщик ОС периодически переключает процессы и потоки (контекстное переключение — тысячи раз в секунду, не миллиарды). На нескольких ядрах задачи могут идти по-настоящему параллельно.
★ Процесс — изолированный экземпляр программы — своё адресное пространство, файлы, права. Браузер, редактор, сервер БД — обычно отдельные процессы.
★ Поток — нить выполнения внутри одного процесса: общая память, свой стек. Пример: интерфейс в главном потоке, загрузка файла в фоновом. В Chrome вкладки чаще выделены в отдельные процессы (изоляция), а не только в потоки — см. таблицу ниже.
Процесс — автономный "контейнер"
Особенности:
- Имеет собственное адресное пространство — одна программа не может читать память другой напрямую,
- Обладает дескрипторами ресурсов — открытые файлы, сокеты, окна,
- Запускается из исполняемого файла и имеет точку входа (
main), - Жизненный цикл управляется ОС — создание, приостановка, завершение.
Примеры процессов:
| Процесс | Команда запуска | Что происходит |
|---|---|---|
explorer.exe | Автозапуск при входе в Windows | Управляет рабочим столом, проводником, панелью задач |
chrome | google-chrome | Создаёт несколько процессов: браузер, рендереры (по одному на вкладку), GPU, утилиты |
postgres | sudo systemctl start postgresql | Главный процесс (postmaster) порождает дочерние для каждого подключения |
notepad.exe | Двойной клик по .txt | Независимый процесс: закрытие одного блокнота не влияет на другой |
Связь процессов:
- Родительский процесс создаёт дочерний через
fork()(Linux) илиCreateProcess()(Windows), - Процессы могут обмениваться данными через:
— файлы,
— сокеты (локальные или сетевые),
— именованные каналы (pipe,named pipe),
— разделяемую память (требует синхронизации).
Поток — "нить исполнения" внутри процесса
Особенности:
- Все потоки одного процесса делят общую память — глобальные переменные, кучу, открытые файлы,
- Каждый имеет собственный стек — для локальных переменных и возвратов из функций,
- Переключение между потоками быстрее, чем между процессами (не требуется переключение адресного пространства),
- Потоки одного процесса могут блокировать друг друга, если работают с общими данными без синхронизации.
Примеры потоков:
| Сценарий | Потоки в действии |
|---|---|
| Веб-сервер (Node.js) | Один основной поток (event loop) + воркеры для тяжёлых операций (через worker_threads) |
| Текстовый редактор | Основной поток — интерфейс, фоновый поток — автосохранение каждые 30 секунд |
| Антивирус при сканировании | Один поток читает файлы с диска, другой — проверяет сигнатуры, третий — обновляет прогресс-бар |
| Игровой движок | Поток рендеринга (60 кадров/с), поток физики (120 Гц), поток звука, поток AI противников |
Синхронизация потоков:
mutex(взаимное исключение) — только один поток может входить в критическую секцию,semaphore— ограничение числа одновременных потоков,condition variable— ожидание наступления события ("данные готовы"),atomic operations— операции, которые выполняются неделимо (например,fetch_add).
Визуальная аналогия:
- Процесс — это завод со своим зданием, складом и электропитанием,
- Потоки — рабочие линии внутри завода, использующие общий склад, но работающие независимо.
Процессы обеспечивают изоляцию и стабильность. Потоки обеспечивают производительность и отзывчивость.
У многозадачности есть риски. К примеру, если два потока будут работать с одной и той же переменной, будут ошибки, поэтому используются блокировки, где один поток блокируется и ждёт, пока закончит первый. Для решения проблем одновременной работы потоков, используется многопроцессорность (несколько ядер CPU), и асинхронность (что это такое, изучим чуть позже).
Операционная система
★ Операционная система управляет этим планировщиком (scheduler): кто получит квант времени CPU, с каким приоритетом. Контекстное переключение занимает микросекунды — поэтому смена задач кажется мгновенной. Как ядро создаёт процесс, выделяет память и обрабатывает системные вызовы — Взаимодействие с ОС; обзор функций ОС — Операционная система.