{
 "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 <module>\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",
      " <detached ...>\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 <module>\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
}
