{ "cells": [ { "cell_type": "markdown", "id": "c89738cc", "metadata": {}, "source": [ "# Процесс и его характеристики #" ] }, { "cell_type": "markdown", "id": "1dc01923", "metadata": {}, "source": [ "На этой лекции мы поговорим о том, что такое процесс, узнаем, какие процессы запущены в вашей операционной системе, а также попробуем запустить свой первый Python процесс и поизучаем его характеристики.\n", "\n", "Итак, процесс — это программа, которая запущена в оперативной памяти компьютера. Другими словами, процесс — это набор инструкций, которые выполняются последовательно. В общем случае это действительно так, но в реальности всё немного сложнее. Мы будем погружаться в детали по мере обучения. Итак, каждый процесс, который запущен в операционной системе, имеет свои характеристики.\n", "\n", "Одна из главных характеристик — это идентификатор процесса, или `PID`. При помощи `PID` можно узнать многое о процессе. Каждый процесс занимает некий объем оперативной памяти. Он запрашивает её у системы, она ему её возвращает и аллоцирует. Также у процесса есть стек. Стек используется для вызова функций, для создания локальных переменных у этих функций. А также у каждого процесса есть список открытых файлов, стандартный ввод и стандартный вывод. В своих примерах я буду использовать операционную систему класса Linux и Python 3.\n", "\n", "Давайте попробуем узнать, какие процессы запущены в нашей операционной системе. Для этого нам потребуется консоль и команда `top`. Набираем команду `top`, вводим `enter` и видим результаты в виде таблицы. Команда `top` отображает нам список процессов, которые сейчас функционируют в операционной системе." ] }, { "cell_type": "code", "execution_count": 2, "id": "6f3f3dc1", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[?1h\u001b=\u001b[H\u001b[2J\u001b[mtop - 13:11:15 up 415 days, 5:01, 1 user, load average: 0.00, 0.01, 0.05\u001b[m\u001b[m\u001b[m\u001b[m\u001b[K\n", "Tasks:\u001b[m\u001b[m\u001b[1m 305 \u001b[m\u001b[mtotal,\u001b[m\u001b[m\u001b[1m 1 \u001b[m\u001b[mrunning,\u001b[m\u001b[m\u001b[1m 304 \u001b[m\u001b[msleeping,\u001b[m\u001b[m\u001b[1m 0 \u001b[m\u001b[mstopped,\u001b[m\u001b[m\u001b[1m 0 \u001b[m\u001b[mzombie\u001b[m\u001b[m\u001b[m\u001b[m\u001b[K\n", "%Cpu(s):\u001b[m\u001b[m\u001b[1m 0.9 \u001b[m\u001b[mus,\u001b[m\u001b[m\u001b[1m 0.7 \u001b[m\u001b[msy,\u001b[m\u001b[m\u001b[1m 0.0 \u001b[m\u001b[mni,\u001b[m\u001b[m\u001b[1m 98.5 \u001b[m\u001b[mid,\u001b[m\u001b[m\u001b[1m 0.0 \u001b[m\u001b[mwa,\u001b[m\u001b[m\u001b[1m 0.0 \u001b[m\u001b[mhi,\u001b[m\u001b[m\u001b[1m 0.0 \u001b[m\u001b[msi,\u001b[m\u001b[m\u001b[1m 0.0 \u001b[m\u001b[mst\u001b[m\u001b[m\u001b[m\u001b[m\u001b[K\n", "KiB Mem :\u001b[m\u001b[m\u001b[1m 65805548 \u001b[m\u001b[mtotal,\u001b[m\u001b[m\u001b[1m 23929780 \u001b[m\u001b[mfree,\u001b[m\u001b[m\u001b[1m 1447684 \u001b[m\u001b[mused,\u001b[m\u001b[m\u001b[1m 40428084 \u001b[m\u001b[mbuff/cache\u001b[m\u001b[m\u001b[m\u001b[m\u001b[K\n", "KiB Swap:\u001b[m\u001b[m\u001b[1m 33030140 \u001b[m\u001b[mtotal,\u001b[m\u001b[m\u001b[1m 33030140 \u001b[m\u001b[mfree,\u001b[m\u001b[m\u001b[1m 0 \u001b[m\u001b[mused.\u001b[m\u001b[m\u001b[1m 63250272 \u001b[m\u001b[mavail Mem \u001b[m\u001b[m\u001b[m\u001b[m\u001b[K\n", "\u001b[K\n", "\u001b[7m PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND \u001b[m\u001b[m\u001b[K\n", "\u001b[m11923 root 20 0 0 0 0 S 5.9 0.0 0:36.59 kworker/12+ \u001b[m\u001b[m\u001b[K\n", "\u001b[m17818 mikhayl+ 20 0 495792 68184 8240 S 5.9 0.1 3:52.91 jupyter-no+ \u001b[m\u001b[m\u001b[K\n", "\u001b[m19235 mikhayl+ 20 0 773876 47736 7784 S 5.9 0.1 0:01.98 python3 \u001b[m\u001b[m\u001b[K\n", "\u001b[m\u001b[1m19251 mikhayl+ 20 0 157848 2216 1436 R 5.9 0.0 0:00.04 top \u001b[m\u001b[m\u001b[K\n", "\u001b[m 1 root 20 0 191788 4784 2420 S 0.0 0.0 20:00.34 systemd \u001b[m\u001b[m\u001b[K\n", "\u001b[m 2 root 20 0 0 0 0 S 0.0 0.0 0:04.01 kthreadd \u001b[m\u001b[m\u001b[K\n", "\u001b[m 3 root 20 0 0 0 0 S 0.0 0.0 0:00.62 ksoftirqd/0 \u001b[m\u001b[m\u001b[K\n", "\u001b[m 5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:+ \u001b[m\u001b[m\u001b[K\n", "\u001b[m 8 root rt 0 0 0 0 S 0.0 0.0 0:00.04 migration/0 \u001b[m\u001b[m\u001b[K\n", "\u001b[m 9 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh \u001b[m\u001b[m\u001b[K\n", "\u001b[m 10 root 20 0 0 0 0 S 0.0 0.0 20:57.39 rcu_sched \u001b[m\u001b[m\u001b[K\n", "\u001b[m 11 root rt 0 0 0 0 S 0.0 0.0 2:53.67 watchdog/0 \u001b[m\u001b[m\u001b[K\n", "\u001b[m 12 root rt 0 0 0 0 S 0.0 0.0 2:42.47 watchdog/1 \u001b[m\u001b[m\u001b[K\n", "\u001b[m 13 root rt 0 0 0 0 S 0.0 0.0 0:01.13 migration/1 \u001b[m\u001b[m\u001b[K\n", "\u001b[m 14 root 20 0 0 0 0 S 0.0 0.0 0:00.66 ksoftirqd/1 \u001b[m\u001b[m\u001b[K\n", "\u001b[m 16 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/1:+ \u001b[m\u001b[m\u001b[K\n", "\u001b[m 17 root rt 0 0 0 0 S 0.0 0.0 2:42.38 watchdog/2 \u001b[m\u001b[m\u001b[K\u001b[?1l\u001b>\u001b[25;1H\n", "\u001b[K" ] } ], "source": [ "! top" ] }, { "cell_type": "markdown", "id": "497b15f7", "metadata": {}, "source": [ "Справа мы видим командную строку, при помощи которой были запущены процессы, и в виде колонок в таблице мы видим характеристики процессов. `PID` — идентификатор процесса, пользователь, из-под которого был запущен процесс. Пользователь определяет права, которые будут доступны этому процессу в операционной системе. Также такие важные колонки, как размер виртуальной и физической памяти. Не будем пока вдаваться в подробности, чем она отличается, а также процентные соотношения использования центрального процессора и памяти в процентах.\n", "\n", "Как мы видим, процессов в операционной системе достаточно много, и все они работают параллельно, на первый взгляд, но на самом деле это не так. Планировщик операционной системы выделяет небольшой квант времени каждому процессу, исполняет его и затем происходит переключение между другими процессами. Таким образом, процессы выполняются все последовательно, но из-за того, что квант времени небольшой, нам кажется, что все они выполняются параллельно.\n", "\n", "Давайте попробуем запустить наш первый Python процесс и изучим его характеристики средствами операционной системы." ] }, { "cell_type": "code", "execution_count": null, "id": "af56a5b0", "metadata": {}, "outputs": [], "source": [ "# простой Python процесс\n", "import time\n", "import os\n", "\n", "pid = os.getpid()\n", "while True:\n", " print(pid, time.time())\n", " time.sleep(2)" ] }, { "cell_type": "markdown", "id": "9c56ce33", "metadata": {}, "source": [ "Программа, представленная на слайде, достаточно простая. В ней импортируется пара модулей — `time` и `os`. Затем при помощи вызова функции модуля `os.getpid` мы получаем идентификатор процесса, запоминаем его в переменную `pid` и в бесконечном цикле выводим `pid` нашего процесса, системное время, и спим пару секунд. Давайте попробуем запустить этот код. Посмотрим, как он выполняется в консоли. Я подготовил заранее код. Вот наш код. Исполняем его при помощи команды Python 3." ] }, { "cell_type": "code", "execution_count": 5, "id": "f5f49ba6", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "19255 1642062336.8886158\n", "19255 1642062338.8908966\n", "^C\n", "Traceback (most recent call last):\n", " File \"ex1.py\", line 7, in \n", " time.sleep(2)\n", "KeyboardInterrupt\n" ] } ], "source": [ "! python ex1.py" ] }, { "cell_type": "markdown", "id": "ebd43ffd", "metadata": {}, "source": [ "Мы видим, что запустился процесс. Он вывел `pid 19287`, системное время, и продолжает это делать бесконечно в цикле. Давайте попробуем найти наш процесс в списке всех процессов. Для этого нам поможет команда `ps` с флагами `aux`. Подробную информацию о флагах можно посмотреть в документации. Итак, эта команда отобразила нам список всех процессов. Для того чтобы найти конкретно наш процесс, можно его отфильтровать при помощи команды `grep`. Итак, мы видим наш процесс." ] }, { "cell_type": "code", "execution_count": 10, "id": "e9ea1a7f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "mikhayl+ 19287 0.5 0.0 125020 5696 pts/6 S+ 13:28 0:00 python ex1.py\r\n", "mikhayl+ 19293 0.0 0.0 113128 1176 pts/7 Ss+ 13:29 0:00 /bin/bash -c ps aux | grep 19287\r\n", "mikhayl+ 19295 0.0 0.0 112660 924 pts/7 S+ 13:29 0:00 grep 19287\r\n" ] } ], "source": [ "! ps aux | grep 19287" ] }, { "cell_type": "markdown", "id": "329bbdd3", "metadata": {}, "source": [ "Для того чтобы посмотреть название характеристик, можно вывести первую строчку от результатов вывода команды `ps` при помощи вот такой команды" ] }, { "cell_type": "code", "execution_count": 9, "id": "f2c50933", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\n", "mikhayl+ 19287 0.6 0.0 125020 5696 pts/6 S+ 13:28 0:00 python ex1.py\n", "mikhayl+ 19288 0.0 0.0 113128 1304 pts/7 Ss+ 13:29 0:00 /bin/bash -c ps aux| head -1 ; ps aux | grep 19287\n", "mikhayl+ 19292 0.0 0.0 112660 924 pts/7 S+ 13:29 0:00 grep 19287\n" ] } ], "source": [ "! ps aux| head -1 ; ps aux | grep 19287" ] }, { "cell_type": "markdown", "id": "2be4f197", "metadata": {}, "source": [ "Итак, еще раз, наш процесс с `pid`'ом `19287` виден в результатах вывода команды `ps`. Вот его `pid`. Он потребляет немного центрального процессора. А также одна из важных характеристик — это объем физической памяти. Мы видим, что он занимает почти 6 килобайт. Такой маленький процесс, а уже занимает 6 килобайт памяти. Видим командную строчку, при помощи которой он был запущен.\n", "\n", "Давайте поймем, какую же последовательность команд выполняет наш процесс. Что он вообще делает? Вообще, процессы, когда выполняются в операционной системе, они делают системные вызовы. Системные вызовы выполняют непосредственно ядро операционной системы, а результаты этих системных вызовов возвращаются к процессу, который их вызвал. Например, вывод в консоль, или стандартный вывод — это системный вызов. Для того чтобы посмотреть, какие системные вызовы делает наш процесс, можно воспользоваться командой `strace`, указать ей `pid` нашего процесса. Нужны дополнительные права для этой команды." ] }, { "cell_type": "code", "execution_count": 13, "id": "78edff8a", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "strace: Process 19287 attached\n", "select(0, NULL, NULL, NULL, {1, 430074}) = 0 (Timeout)\n", "write(1, \"19287 1642062820.0185373\\n\", 25) = 25\n", "select(0, NULL, NULL, NULL, {2, 0}) = 0 (Timeout)\n", "write(1, \"19287 1642062822.0211146\\n\", 25) = 25\n", "select(0, NULL, NULL, NULL, {2, 0}^C\n", "strace: Process 19287 detached\n", " \n" ] } ], "source": [ "! strace -p 19287" ] }, { "cell_type": "markdown", "id": "cc4fc432", "metadata": {}, "source": [ "В результатах `strace`'а мы как раз видим то, что вызывается системный вызов `write`. У него есть в аргументах файловый дескриптор 1. Это как раз наш стандартный вывод. А также мы видим, что в этот стандартный вывод попадает `pid` нашего процесса и системное время. Также видим, что для вызова `sleep` используются другие дополнительные системные вызовы. Для выхода используем `Ctrl+C`.\n", "\n", "Итак, мы видим, что процесс во время исполнения наш общается с операционной системой при помощи системных вызовов. Давайте посмотрим еще на список файлов, которые открыты в нашем процессе. Для этого мы можем воспользоваться командой `lsof`. Опять же, указываем `pid` нашего процесса." ] }, { "cell_type": "code", "execution_count": 14, "id": "4bb300a6", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME\r\n", "python 19287 mikhaylovaf cwd DIR 253,2 113 1611044178 /home/mikhaylovaf/projects/python/5. Многопоточное и асинхронное программирование/1. Процессы и потоки\r\n", "python 19287 mikhaylovaf rtd DIR 253,0 262 64 /\r\n", "python 19287 mikhaylovaf txt REG 253,0 11328 610823 /usr/bin/python3.6\r\n", "python 19287 mikhaylovaf mem REG 253,0 106070960 2704 /usr/lib/locale/locale-archive\r\n", "python 19287 mikhaylovaf mem REG 253,0 2127336 33577165 /usr/lib64/libc-2.17.so\r\n", "python 19287 mikhaylovaf mem REG 253,0 1139680 33577173 /usr/lib64/libm-2.17.so\r\n", "python 19287 mikhaylovaf mem REG 253,0 14872 33577199 /usr/lib64/libutil-2.17.so\r\n", "python 19287 mikhaylovaf mem REG 253,0 19776 33577171 /usr/lib64/libdl-2.17.so\r\n", "python 19287 mikhaylovaf mem REG 253,0 144792 33577191 /usr/lib64/libpthread-2.17.so\r\n", "python 19287 mikhaylovaf mem REG 253,0 3144192 34017354 /usr/lib64/libpython3.6m.so.1.0\r\n", "python 19287 mikhaylovaf mem REG 253,0 164112 33577158 /usr/lib64/ld-2.17.so\r\n", "python 19287 mikhaylovaf mem REG 253,0 26254 33577463 /usr/lib64/gconv/gconv-modules.cache\r\n", "python 19287 mikhaylovaf 0u CHR 136,6 0t0 9 /dev/pts/6\r\n", "python 19287 mikhaylovaf 1u CHR 136,6 0t0 9 /dev/pts/6\r\n", "python 19287 mikhaylovaf 2u CHR 136,6 0t0 9 /dev/pts/6\r\n" ] } ], "source": [ "! lsof -p 19287" ] }, { "cell_type": "markdown", "id": "7e2b8b4d", "metadata": {}, "source": [ "Список достаточно большой. Как минимум, когда наш Python интерпретатор запускает нашу программу, открываются дополнительные системные библиотеки. Они отображены тоже в результатах команды `lsof`. Но самое главное, что нас сейчас интересует, — это стандартный поток ввода, вывода и поток ошибок. Это файловые дескрипторы 0, 1 и 2. Мы видим, что они равны терминалу.\n", "\n", "Давайте попробуем прервать выполнение программы при помощи `Ctrl+C` и перенаправим стандартный вывод в файл. Делается это при помощи такой команды в любой файл." ] }, { "cell_type": "code", "execution_count": 15, "id": "af824409", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "^C\r\n", "Traceback (most recent call last):\r\n", " File \"ex1.py\", line 7, in \r\n", " time.sleep(2)\r\n", "KeyboardInterrupt\r\n" ] } ], "source": [ "! python ex1.py > log.txt" ] }, { "cell_type": "markdown", "id": "0861b697", "metadata": {}, "source": [ "Снова поищем наш процесс при помощи команды ps. Его pid = 19347." ] }, { "cell_type": "code", "execution_count": 16, "id": "444d66fc", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\n", "mikhayl+ 19347 0.0 0.0 125028 5700 pts/6 S+ 13:38 0:00 python ex1.py\n", "mikhayl+ 19366 0.0 0.0 113128 1300 pts/8 Ss+ 13:40 0:00 /bin/bash -c ps aux| head -1 ; ps aux | grep ex1.py\n", "mikhayl+ 19370 0.0 0.0 112660 924 pts/8 S+ 13:40 0:00 grep ex1.py\n" ] } ], "source": [ "! ps aux| head -1 ; ps aux | grep ex1.py" ] }, { "cell_type": "markdown", "id": "06385847", "metadata": {}, "source": [ "И при помощи `lsof` выведем список открытых файлов." ] }, { "cell_type": "code", "execution_count": 17, "id": "9282bc58", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME\r\n", "python 19347 mikhaylovaf cwd DIR 253,2 128 1611044178 /home/mikhaylovaf/projects/python/5. Многопоточное и асинхронное программирование/1. Процессы и потоки\r\n", "python 19347 mikhaylovaf rtd DIR 253,0 262 64 /\r\n", "python 19347 mikhaylovaf txt REG 253,0 11328 610823 /usr/bin/python3.6\r\n", "python 19347 mikhaylovaf mem REG 253,0 106070960 2704 /usr/lib/locale/locale-archive\r\n", "python 19347 mikhaylovaf mem REG 253,0 2127336 33577165 /usr/lib64/libc-2.17.so\r\n", "python 19347 mikhaylovaf mem REG 253,0 1139680 33577173 /usr/lib64/libm-2.17.so\r\n", "python 19347 mikhaylovaf mem REG 253,0 14872 33577199 /usr/lib64/libutil-2.17.so\r\n", "python 19347 mikhaylovaf mem REG 253,0 19776 33577171 /usr/lib64/libdl-2.17.so\r\n", "python 19347 mikhaylovaf mem REG 253,0 144792 33577191 /usr/lib64/libpthread-2.17.so\r\n", "python 19347 mikhaylovaf mem REG 253,0 3144192 34017354 /usr/lib64/libpython3.6m.so.1.0\r\n", "python 19347 mikhaylovaf mem REG 253,0 164112 33577158 /usr/lib64/ld-2.17.so\r\n", "python 19347 mikhaylovaf mem REG 253,0 26254 33577463 /usr/lib64/gconv/gconv-modules.cache\r\n", "python 19347 mikhaylovaf 0u CHR 136,6 0t0 9 /dev/pts/6\r\n", "python 19347 mikhaylovaf 1w REG 253,2 0 1611044181 /home/mikhaylovaf/projects/python/5. Многопоточное и асинхронное программирование/1. Процессы и потоки/log.txt\r\n", "python 19347 mikhaylovaf 2u CHR 136,6 0t0 9 /dev/pts/6\r\n" ] } ], "source": [ "! lsof -p 19347" ] }, { "cell_type": "markdown", "id": "8966c1e8", "metadata": {}, "source": [ "Результат команды `lsof` доказывает нам, что стандартный вывод у нашего процесса поменялся на файл.\n", "\n", "Итак, на этой лекции мы посмотрели и узнали, что такое процесс, как выглядит процесс в нашей операционной системе. Мы узнали о том, как работает процесс, что он делает системные вызовы. Также изучили характеристики запущенного `python` процесса и узнали, как работают команды `top`, `ps`, `lsof` и `strace`.\n", "\n", "На следующей лекции мы продолжим изучать процессы и узнаем, как создавать дочерние процессы на Python." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 5 }