Python – достаточно простой и популярный язык программирования с объектно-ориентированной парадигмой. Он является функциональным и поддерживает огромное количество разнообразных фреймворков и библиотек. Изучать Python и его инструменты рекомендуется как новичкам в программировании, так и тем, кто уже имеет опыт в разработке программного обеспечения.
В процессе использования the Python предстоит решать самые разные задачи. Современные приложения проектируются так, чтобы их задачи выполнялись параллельно. Для этого в the Python имеется специальная библиотека. Она называется threading. Далее она будет рассмотрена более подробно. Также предстоит разобраться в работе многопоточности в the Python.
Принцип работы многопоточности
В информатике поток – это минимальная единица работы, которая запланирована для выполнения операционной системой. Он имеет такие особенности как:
- существование внутри процесса;
- в одном процессе допускается несколько потоков;
- поток в одном процессе разделяет состояние и память родительского процесса.
Многопоточность – это выполнение приложения сразу в нескольких потоках, которые отвечают за выполнения ее функций одновременно.
Многопоточная разработка напоминает мультипроцессорную. Эти две концепции похожи между собой. Только в первом случае программное обеспечение работает с потоками, во втором – непосредственно с процессами. Разница между этими компонентами элементарна: потоки обладают общей памятью, поэтому изменения в одном из них видны в других. Процессы же используют разные области памяти.
В одноядерных процессорах операции из разных потоков выполняются не параллельно. Одно ядро способно выполнить только одну операцию в заданную единицу времени. Из-за того, что команды обрабатываются очень быстро, складывается впечатление, что они выполняются параллельно. Такое поведение называется псевдопараллельностью. Реально параллельная работа поддерживается только на многоядерных процессорах. Там каждое ядро способно выполнять операции независимо от других.
Threading – для чего нужен
В the Python threading представляет собой специальную библиотеку для многопоточности. Изначально в рассматриваемом языке программирования используется GIL, который является однопоточным. Все потоки, которые создаются через threading, будут функционировать внутри GIL-потока. Они обрабатываются только одним ядром.
Если приложению необходимо выполнять одновременно несколько задач, предстоит пользоваться упомянутой библиотекой. Также threading потребуется в следующих ситуациях:
- Обработка нажатия кнопки в графическом интерфейсе. Пример – через Tkinter. Если по нажатию кнопки требуется осуществлять множество действий, которые требуют времени, соответствующие операции выполняются в другом потоке. Это необходимо для устранения вероятности «подвисания» графического интерфейса.
- Приложение функционирует одновременно с подключением нескольких устройств. Они могут быть подсоединены к разным COM-портам.
- Загрузка файлов из сети и одновременная обработка уже загруженных элементов.
Это лишь несколько наглядных примеров. Если требуется добиться работы приложения одновременно на нескольких физических ядрах процессора, рекомендуется обратить внимание на the Python библиотеку (модуль) – Multiprocessing.
У threading есть определенные преимуществе перед Multiprocessing:
- Простое использование. Начать работу с этой библиотекой достаточно легко.
- Простота передачи данных из потока в основное приложение. Допускается использование глобальных переменных, но в этом случае программное обеспечение должно быть грамотно спроектировано: без ошибок, которые связаны с «Состоянием гонки».
Если приложение будет запускаться на одноядерном компьютере или нагрузка на процессор окажется небольшой, threading – оптимальное решение для работы с потоками.
Параллелизм – это…
Параллелизм дает возможность нескольким вычислениям на устройстве работать одновременно в рамках единого приложения. Подобного поведения в the Python обычно удается добиться несколькими способами:
- через многопоточность threading;
- при помощи multiprocessing;
- за счет асинхронного ввода-вывода с модулем asyncio.
Асинхронный ввод-вывод не относится ни к потоковым, ни к многопроцессорным. Это однопоточная однопроцессорная парадигма, которая не имеет отношения к параллельным вычислениям.
Подключение threading
Для начала работы с библиотекой threading в the Python не придется ничего дополнительно устанавливать. Упомянутый инструмент – это стандартный модуль. Он поставляется вместе с интерпретатором. Его потребуется всего лишь подключить через специальную команду:
Import threading
Работа с потоками возможна за счет создания экземпляров класса Thread. Чтобы сделать отдельный поток, потребуется написать экземпляр класса, а затем применить к нему метод start. Ниже можно увидеть наглядный пример:
Здесь функция mydef запущена в отдельном потоке. В виде ее аргументов были переданы числа 1 и 2.
Threading.Thread()
The threading.Thread() – конструкция, позволяющая создавать новые потоки путем создания экземпляров класса Thread. Ее синтаксическая форма в the Python выглядит так:
Здесь:
- Group. Имеет значение None. Зарезервирована данная функция для будущего расширения в процессе реализации класса ThreadGroup.
- Target – функция, выполняемая в потоке через метод run(). Если передается значение None, ничего вызываться не будет.
- Name – потоковое имя. По умолчанию оно принимает значение «Thread-X», где X – это десятичное число. Имя задается разработчиком самостоятельно, вручную.
- Args – кортеж, в котором будут храниться аргументы, передаваемые в вызываемую функцию.
- Kwargs – словарь для хранения аргументов, передаваемых в функцию.
- Daemon – параметр, указывающий, является ли поток демоническим. По умолчанию у него установлено значение None. В этом случае свойство daemonic наследуется от текущего потока. Разработчик способен самостоятельно устанавливать значение соответствующего параметра.
Daemon требует более подробного рассмотрения. Не все разработчики быстро понимают, что этот параметр собой представляет.
Несколько слов о демонах
Изучая threading в the Python, необходимо не забывать о демонах. Так называют процессы, работающие в фоновом режиме. В рассматриваемом языке программирования для него имеется более конкретное название: поток демона или демонический поток. В отличие от обычных потоков, демонический завершит работу, если закрыть приложение. Программа не станет ожидать завершения daemon-потока. При ее закрытии соответствующие потоки будут уничтожены, независимо от того, в каком именно состоянии они не находились.
Дэймон-потоки используются для выполнения операций, которые работают в бесконечных циклах. В других ситуациях чаще всего используются обычные потоки, которые могут задержать закрытие программы до тех пор, пока не завершат выполнение всех операций.
Пример использования демонического потока – когда приложение полностью перезаписывает содержимое документа, а механизм этой операции реализован в упомянутом потоке, то при неожиданном выходе из программного обеспечения данные будут утрачены.
Дэймон-потоки часто помещаются в функции по рисованию графических интерфейсов. Так называется бесконечная операция, которая завершается сразу после выхода из программы. Если использовать обычный поток, это помешает закрыть программное обеспечение.
Методы для работы с потоками
В the Python для создания и управления потоками применяются разнообразные методы класса Thread. С их помощью возможно не только манипулирование, но и определение дальнейшего потокового поведения. Далее предстоит рассмотреть существующие методы, помогающие работать с многопоточностью.
Start()
Start() – первый и самый основной метод the Python в рассматриваемом вопросе. Он применяется для того, чтобы запускать созданный ранее поток. После использования threading.Thread() появляется новый поток, но он неактивен. Чтобы запустить его в программном обеспечении, обязательно применение start-метода. Выглядит это так:
Пример выше работает так, что, пока метод start не вызван программой, в ней не будет запускаться функция myfunc.
Join()
Join() – еще один метод в the Python. Он отвечает за блокировку выполнения потока, который его вызвал. Происходит это до тех пор, пока не завершится поток, метод которого был вызван программным обеспечением. Это значит, что если в thread1 был вызван метод thread2:thread2.join(), thread1 будет приостановлен. Он возобновит работу, как только thread2 будет завершен.
Соответствующий метод позволяет заставлять приложение дожидаться завершения демонического потока. Пример – при вызове метода в основном thread программа не завершается до тех пор, пока «демон» не будет выполнен.
Join() поддерживает аргумент timeout. По умолчанию у него значение установлено на значении None. Разработчик имеет право передать в него число с плавающей запятой. Если у аргумента установлено значение по умолчанию, значит the thread будет приостановлен, пока выполняется поток метода. При передаче в виде аргумента числового значения, метод join() получит время ожидания. Когда оно подойдет к концу, thread продолжит свое функционирование.
Run()
Run() – метод в the Python, помогающий описывать выполняемые в thread операции. Он применяется при явном создании экземпляра класса.
Выше можно увидеть наглядный пример применения run().
Is_alive()
Метод, позволяющий проверить выполнение thread в текущий момент времени. Он часто используется вместе с join(). С помощью is_alive() удастся грамотно управлять выполнением демонических потоков, не давая им неожиданно завершать работу при закрытии программного обеспечения.
Выше – пример практического применения is_alive() с подробными комментариями.
Потоковая остановка
Иногда рассматриваемый компонент, работающий в фоне, необходимо остановить. Пример – thread с наличием в функции run бесконечного цикла. В основном приложении требуется прекратить его функционирование. Самый простой вариант – это использование специальной переменной в the Python. Она называется stop.
В этом случае необходимо:
- Через stop. В бесконечном цикле создается постоянная проверка этой переменной. Если ее значение равняется true, цикл завершается.
- Нельзя использовать функции, способные блокировать выполнение на длительный промежуток времени. Нужно задействовать timeout.
Вот пример приложения, в котором применяется потоковая остановка:
Тут используется глобальная переменная stop. Когда необходимо остановить the thread, ей присваивается значение True. После этого останется лишь дождаться непосредственной реализации заданной «команды».
Состояние гонки
Race condition или «состояние гонки» – ошибка, которая возникает при неправильном проектировании многопоточного программного обеспечения. Она появляется, когда несколько потоков обращаются к одной и той же информации. Пример – переменная хранит число, которое одновременно пытаются скорректировать thread1 и thread2. Это приведет к непредсказуемым результатам и даже ошибкам/сбоям.
Распространены ситуации, при которых один thread проверяет значения переменных на выполнение условия для совершения того или иного действия, но в процессе реализации этой операции в работу вмешивается второй thread, изменяющий значение переменной. Это влечет за собой получение конечным пользователем неправильных результатов. Вот – наглядный пример такой ситуации:
Состояние гонки – ситуация, приводящая к самым разным проблемам:
- утечке памяти;
- потере информации;
- уязвимостям в безопасности запускаемого программного обеспечения;
- взаимным потоковым блокировкам;
- получению ошибочных (неверных) данных.
Предотвратить состояние гонки помогает управление доступом к общим ресурсам. Его необходимо изучить более детально.
Доступ к общим ресурсам – lock
Для устранения состояния гонки необходимо воспользоваться блокировкой – threading.Lock(). Она не дает нескольким потокам работать с одной и той же информацией. Lock отвечает за защиту данных от одновременного доступа.
Threading.Lock() возвращает объект, который является своеобразной «дверью». Она будет запираться, если в комнате кто-то находится. Это значит, если потом использовал Lock (осуществлен вход в комнату), другой поток должен вынужденно находиться в ожидании отказа от «предыдущего thread» (в ожидании выхода из комнаты). Полученный объект будет обладать двумя методами – release() и acquire().
Acquire()
Acquire() – это метод, который дает возможность the thread получить блокировку. Он обладает двумя аргументами: blocking и timeout. При вызове метода с аргументом blocking = true (параметр, устанавливаемый по умолчанию) Lock блокируется до тех пор, пока он не будет разблокирован. Возвращаемое значение окажется true. Если object уже заблокирован, поток окажется приостановленным. Он будет ожидать разблокировки, после чего самостоятельно его заблокирует.
Если будет вызван аргумент с False, при условии, что объект Lock разблокирован, метод будет блокировать его, а затем возвращать значение true. Если Lock заблокирован, метод ничего делать не будет. В приложении просто возвращается значение False.
Аргумент timeout (по умолчанию -1), предусматривает возможность изменения, только если аргумент blocking имеет значение true. Если в виде параметра передается положительное значение, объект блокируется на указанный промежуток времени (в секундах) с учетом ожидания блокировки. Аргумент по умолчанию указывает методу на необходимость применения бесконечного ожидания.
Release()
Release() – метод, который отвечает за разблокировку Lock. Интерпретатор позволит вызвать его из любого потока, а не только из того, который заблокировал упомянутый ранее объект на текущий момент.
The release() ничего не возвращает. Он вызывает ошибку в приложении RuntimeError, если метод будет вызван, когда Lock уже разблокирован. Ниже представлен наглядный пример использования release():
В примере выше:
- Создается Lock-объект. Он поможет безопасно считывать и корректировать информацию.
- В виде данных, подлежащих блокировке, выступает одна переменная x.
- После продемонстрировано безопасное изменение информации: сначала при помощи acquire требуется дождаться своей очереди к ним, после чего происходит ее корректировка. Она заключается в перезаписи значения переменной.
- Система выводит значение в консоль.
- Далее происходит освобождение доступа для других потоков.
Если все потоки, которым потребуется доступ к данным x, предусматривают использование Lock, получится устранить ситуацию гонки.
Deadlock
При использовании the Lock появляется серьезная проблема. Она нередко приводит к полному прекращению функционирования программного обеспечения. Если вызвать acquire(), когда the Lock уже разблокирован, то thread, который вызвал acquire(), будет находиться в ожидании вызова release() потоком, заблокировавший объект.
Если один thread вызывает блокировку (method) несколько раз подряд, его выполнение прекращается. Это происходит до тех пор, пока поток самостоятельно не обратится к вызову release(). Это невозможно, потому что выполнение the thread приостановлено. Ситуация указывает на то, что исходное приложение попадает под бесконечную блокировку.
Самоблокировка – процесс, который можно предотвратить. Для этого потребуется удалить лишний вызов acquire(). Подобная операция возможна не всегда.
Самоблокировка происходит по разным причинам. К ним можно отнести:
- появление ошибок, когда Lock остается со статусом «блокировка активирована»;
- неправильное проектирование приложения – когда одна команда вызывается другой функцией, у которой нет блокировки.
При появлении проблем достаточно воспользоваться специальной конструкцией – try-finally. Вместо нее допускается использование оператора with:
Try-finally – конструкция, с помощью которой получится удалить блокировку, даже если возникнут ошибки. Это позволяет миновать the deadblock. Вот наглядный пример реализации концепции:
С помощью the try-finally гарантируется, что код в finally всегда исполняется, независимо от ошибок и результатов, полученных в блоке try. В случае, когда блокировка вызвана неправильным проектированием, соответствующий прием не работает. Для исправления ситуации был создан специальный объект RLock.
RLock
Если Lock заблокирован, он будет блокировать любые потоки the Python, которые попытались сделать то же самое, даже если этот thread является владельцем блокировки на текущий момент. Вот пример кода, который поможет лучше понять ситуацию:
Функционирование данного фрагмента кода допускается, но существует одна проблема. Она заключается в том, что в процессе вызова функции both_parts, в ней будут вызваны команды part1 и part2. Между обращением к соответствующим операциям допускается ситуация, когда какой-нибудь thread получит доступ к информации и поменяет ее.
Для устранения соответствующей ситуации необходимо заблокировать lock1. При переписывании программного кода в both_parts получится следующий результат:
Идея здесь простая: внешняя both_parts блокирует поток на время выполнения функции part1 part2. Каждая команда также блокирует поток для суммирования своей части объекта. The Lock не позволяет это сделать. В итоге код приводит к зависанию программного обеспечения. Это связано с тем, что для Lock не имеет значения, где в потоке был вызван acquire().
RLock будет блокировать поток только тогда, когда объект заблокирован другим thread. С его помощью удается полностью исключить потоковую самоблокировку.
Использование RLock требуется для того, чтобы управлять вложенным доступом к разделяемым объектам. Для решения возникшей проблемы с Lock в приведенном ранее примере достаточно заменить строку lock1 = threading.Lock() на lock1 = threading.RLock().
В процессе работы необходимо запомнить, что, хоть вызов acquire() возможен несколько раз, методу release() потребуется аналогичного количества обращений. Каждый вызов acquire() влечет за собой увеличение рекурсии на единицу. При использовании release() она уменьшается на точно такое же значение.
Очереди и информационная передача
Класс Queue используется для того, чтобы можно было передавать данные с помощью очередей. Он располагается в библиотеке queue, которая импортируется командой:
From queue import Queue.
Данная библиотека включает в себя все инструменты, которые пригодятся для передачи информации между потоками. Она отвечает за реализацию необходимых механизмов блокировки.
Класс the Queue отвечает в первую очередь за реализацию FIFO, который функционирует так: первый компонент, вошедший в очередь, первый из него выходит. Эта очередь сравнима с вертикальной полой трубой, в которую сверху бросаются различные предметы.
У Queue предусматривается параметр maxsize. Он способен принимать исключительно целочисленные значения. Используется для указания предельного количества элементов, допустимых для помещения в очередь. При достижении максимума добавление в очередь блокируется. Это происходит до тех пор, пока в ней не появится свободное пространство (не освободится место). Если у maxsize значение больше или равно 0, очередь бесконечна.
Для взаимодействия с очередями применяется Event – это объект модуля threading. Он дает возможность потоку выполнить необходимые операции при получении сигнала от другого the thread. Поток не обязательно должен останавливать свою работу на время ожидания сигнала.
Qsize()
Для передачи информации и работы с очередями в the Python thread используются отдельные методы. Первый – это qsize(). Он отвечает за возврат примерного размера очереди. Здесь необходимо понимать следующее:
- если qsize() > 0, следующий метод get() все равно может попасть под блокировку;
- если qsize() < maxsize, следующие put() допускает блокировку.
Это не единственный метод для работы с передачей данных. Далее будут представлены другие концепции, которые применяются программистами.
Empty()
Empty() – метод, проверяющий очередь на факт содержания чего-либо. Если она пуста, система возвращает значение true. В противном случае – результатом станет false. Это не гарантирует того, что get() или put() не окажутся заблокированными.
Full()
Full() отвечает за проверку заполненности очереди. Если она заполнена, возвращается true-значение, в противном случае система выдаст результат false. Как и в прошлом случае, возврат true/false не дает никаких гарантий, что put() и get() не попадут под блокировку.
Put()
Put() – отвечает за помещение нового объекта в очередь. У него предусматривается обязательный аргумент item, а также два необязательных: block = True, timeout = None. Выглядит этот метод так:
В зависимости от используемых аргументов, ожидание места в очереди ведет себя по-разному. Допускаются следующие варианты развития событий:
- Если параметр the block будет иметь значение True, а the timeout – None, объект, который требуется загрузить в очередь, будет бесконечно ждать свободного пространства.
- Если the timeout > 0, ожидание свободного места длится не более указанного количества секунд. Если за этот период пространство не появилось, возбуждается исключение.
- При the block со значением False аргумент timeout игнорируется. Элемент может быть помещен в очередь только при наличии свободного места. В противном случае система сразу генерирует исключение.
Ниже – пример создания очереди в the Python с дальнейшим добавлением в нее компонента:
Также есть метод put(nowait). Он работает так же, как и put(item, False). С его применением осуществляется помещение элемента в очередь только при наличии места. Если оно отсутствует, приложение вызовет исключение.
Get()
Get() – отвечает за удаление и возврат элемента из очереди. У него два необязательных аргумента – как и у put:
Поведение также зависит от значений аргументов:
- При значении по умолчанию метод ожидает объект из очереди, пока он не станет доступным.
- Если timeout – это положительное число, объект из очереди ожидается заданное время. Как только оно закончится, система выдаст исключение.
- Если block имеет значение false – компонент возвращается, только если он является недоступным. В противном случае будет вызвано исключение. Аргумент timeout будет игнорироваться.
Также существует get_nowait(). Он работает точно также, как и get(False).
Task_done()
Работает вместе с методом the join(). Он указывает, что поставленная ранее задача была выполнена. После получения каждого элемента из очереди, требуется вызвать task_done() для уменьшения счетчика задач. Если система обращается к нему больше, чем количество элементов в очереди, появляется исключение ValueError.
Join()
Join() – метод, отвечающий за блокировку потока до тех пор, пока все элементы очереди не будут получены и обработаны. Каждый раз, когда в очередь добавляется новый компонент, счетчик нерешенных задач увеличивается. При вызове task_done он уменьшается и показывает, что обработка компонента в очереди успешно завершена – возможен переход к следующему. При счетчике, равном нулю, блокировка с потока снимается. Ниже – наглядный пример реализации метода:
В данном the python threading примере операции осуществляются в одном потоке. Обычно один поток пишет данные в очередь, затем – ждет их обработки с помощью join(). Другой поток при получении каждого нового значения вызывает task_done.
Интересует Python? Добро пожаловать на курс в Otus!
<!DOCTYPE html>
<html dir="ltr" lang="ru-RU">
<head>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="profile" href="http://gmpg.org/xfn/11" />
<title>Работа с потоками в Питоне OTUS</title>
<!-- All in One SEO 4.5.2.1 - aioseo.com -->
<meta name="description" content="Python – достаточно простой и популярный язык программирования с объектно-ориентированной парадигмой. Он является функциональным и поддерживает огромное количество разнообразных фреймворков и библиотек. Изучать Python и его инструменты рекомендуется как новичкам в программировании, так и тем, кто уже имеет опыт в разработке программного обеспечения. В процессе использования the Python предстоит решать самые разные задачи. Современные приложения" />
<meta name="robots" content="max-image-preview:large" />
<link rel="canonical" href="https://otus.ru/journal/rabota-s-potokami-v-pitone/" />
<meta name="generator" content="All in One SEO (AIOSEO) 4.5.2.1" />
<script type="application/ld+json" class="aioseo-schema">
{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#article","name":"\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u0432 \u041f\u0438\u0442\u043e\u043d\u0435 OTUS","headline":"\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u0432 \u041f\u0438\u0442\u043e\u043d\u0435","author":{"@id":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/#author"},"publisher":{"@id":"https:\/\/otus.ru\/journal\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/otus.ru\/journal\/wp-content\/uploads\/2024\/02\/oj-1080x720-13.jpg","width":2245,"height":1587},"datePublished":"2024-02-04T10:57:07+00:00","dateModified":"2024-02-04T10:57:10+00:00","inLanguage":"ru-RU","mainEntityOfPage":{"@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#webpage"},"isPartOf":{"@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#webpage"},"articleSection":"\u041f\u043e\u043b\u0435\u0437\u043d\u043e\u0435, Python"},{"@type":"BreadcrumbList","@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/otus.ru\/journal\/#listItem","position":1,"name":"\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430","item":"https:\/\/otus.ru\/journal\/","nextItem":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#listItem"},{"@type":"ListItem","@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#listItem","position":2,"name":"\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u0432 \u041f\u0438\u0442\u043e\u043d\u0435","previousItem":"https:\/\/otus.ru\/journal\/#listItem"}]},{"@type":"Organization","@id":"https:\/\/otus.ru\/journal\/#organization","name":"\u041e\u0442\u0443\u0441 \u043e\u043d\u043b\u0430\u0439\u043d-\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435","url":"https:\/\/otus.ru\/journal\/","sameAs":["https:\/\/www.youtube.com\/channel\/UCetgtvy93o3i3CvyGXKFU3g"],"contactPoint":{"@type":"ContactPoint","telephone":"+74999389202","contactType":"Customer Support"}},{"@type":"Person","@id":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/#author","url":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/","name":"A. Pavlenko","image":{"@type":"ImageObject","@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/d4c499a104d7c2522fa41f89e6819499?s=96&d=mm&r=g","width":96,"height":96,"caption":"A. Pavlenko"}},{"@type":"WebPage","@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#webpage","url":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/","name":"\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u0432 \u041f\u0438\u0442\u043e\u043d\u0435 OTUS","description":"Python \u2013 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u043e\u0439. \u041e\u043d \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. \u0418\u0437\u0443\u0447\u0430\u0442\u044c Python \u0438 \u0435\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043d\u043e\u0432\u0438\u0447\u043a\u0430\u043c \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438, \u0442\u0430\u043a \u0438 \u0442\u0435\u043c, \u043a\u0442\u043e \u0443\u0436\u0435 \u0438\u043c\u0435\u0435\u0442 \u043e\u043f\u044b\u0442 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f the Python \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u0440\u0435\u0448\u0430\u0442\u044c \u0441\u0430\u043c\u044b\u0435 \u0440\u0430\u0437\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f","inLanguage":"ru-RU","isPartOf":{"@id":"https:\/\/otus.ru\/journal\/#website"},"breadcrumb":{"@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#breadcrumblist"},"author":{"@id":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/#author"},"creator":{"@id":"https:\/\/otus.ru\/journal\/author\/a-pavlenko\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/otus.ru\/journal\/wp-content\/uploads\/2024\/02\/oj-1080x720-13.jpg","@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#mainImage","width":2245,"height":1587},"primaryImageOfPage":{"@id":"https:\/\/otus.ru\/journal\/rabota-s-potokami-v-pitone\/#mainImage"},"datePublished":"2024-02-04T10:57:07+00:00","dateModified":"2024-02-04T10:57:10+00:00"},{"@type":"WebSite","@id":"https:\/\/otus.ru\/journal\/#website","url":"https:\/\/otus.ru\/journal\/","name":"OTUS JOURNAL","description":"Blog about IT","inLanguage":"ru-RU","publisher":{"@id":"https:\/\/otus.ru\/journal\/#organization"}}]}
</script>
<!-- All in One SEO -->
<link rel='dns-prefetch' href='//otus.ru' />
<link rel='dns-prefetch' href='//fonts.googleapis.com' />
<link rel='stylesheet' id='wp-block-library-css' href='https://otus.ru/journal/wp-includes/css/dist/block-library/style.min.css?ver=6.4.7' type='text/css' media='all' />
<style id='classic-theme-styles-inline-css' type='text/css'>
/*! This file is auto-generated */
.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none}
</style>
<style id='global-styles-inline-css' type='text/css'>
body{--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}
.wp-block-navigation a:where(:not(.wp-element-button)){color: inherit;}
:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}
:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}
.wp-block-pullquote{font-size: 1.5em;line-height: 1.6;}
</style>
<link rel='stylesheet' id='wbcr-comments-plus-url-span-css' href='https://otus.ru/journal/wp-content/plugins/clearfy/components/comments-plus/assets/css/url-span.css?ver=2.2.0' type='text/css' media='all' />
<link rel='stylesheet' id='wpel-style-css' href='https://otus.ru/journal/wp-content/plugins/wp-external-links/public/css/wpel.css?ver=2.59' type='text/css' media='all' />
<link rel='stylesheet' id='ez-toc-css' href='https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/css/screen.min.css?ver=2.0.61' type='text/css' media='all' />
<style id='ez-toc-inline-css' type='text/css'>
div#ez-toc-container .ez-toc-title {font-size: 120%;}div#ez-toc-container .ez-toc-title {font-weight: 500;}div#ez-toc-container ul li {font-size: 95%;}div#ez-toc-container nav ul ul li {font-size: 90%;}
.ez-toc-container-direction {direction: ltr;}.ez-toc-counter ul{counter-reset: item ;}.ez-toc-counter nav ul li a::before {content: counters(item, ".", decimal) ". ";display: inline-block;counter-increment: item;flex-grow: 0;flex-shrink: 0;margin-right: .2em; float: left; }.ez-toc-widget-direction {direction: ltr;}.ez-toc-widget-container ul{counter-reset: item ;}.ez-toc-widget-container nav ul li a::before {content: counters(item, ".", decimal) ". ";display: inline-block;counter-increment: item;flex-grow: 0;flex-shrink: 0;margin-right: .2em; float: left; }
</style>
<link rel='stylesheet' id='contentberg-fonts-css' href='https://fonts.googleapis.com/css?family=Roboto%3A400%2C500%2C700%7CPT+Serif%3A400%2C400i%2C600%7CIBM+Plex+Serif%3A500' type='text/css' media='all' />
<link rel='stylesheet' id='contentberg-core-css' href='https://otus.ru/journal/wp-content/themes/contentberg/style.css?ver=1.8.3' type='text/css' media='all' />
<link rel='stylesheet' id='contentberg-lightbox-css' href='https://otus.ru/journal/wp-content/themes/contentberg/css/lightbox.css?ver=1.8.3' type='text/css' media='all' />
<link rel='stylesheet' id='font-awesome-css' href='https://otus.ru/journal/wp-content/themes/contentberg/css/fontawesome/css/font-awesome.min.css?ver=1.8.3' type='text/css' media='all' />
<script type="text/javascript" id="breeze-prefetch-js-extra">
/* <![CDATA[ */
var breeze_prefetch = {"local_url":"https:\/\/otus.ru\/journal","ignore_remote_prefetch":"1","ignore_list":["\/wp-admin\/"]};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/breeze/assets/js/js-front-end/breeze-prefetch-links.min.js" id="breeze-prefetch-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery.min.js" id="jquery-core-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery-migrate.min.js" id="jquery-migrate-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/lazysizes.js" id="lazysizes-js"></script>
<link rel="https://api.w.org/" href="https://otus.ru/journal/wp-json/" /><link rel="alternate" type="application/json" href="https://otus.ru/journal/wp-json/wp/v2/posts/9121" /><link rel='shortlink' href='https://otus.ru/journal/?p=9121' />
<link rel="alternate" type="application/json+oembed" href="https://otus.ru/journal/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fotus.ru%2Fjournal%2Frabota-s-potokami-v-pitone%2F" />
<link rel="alternate" type="text/xml+oembed" href="https://otus.ru/journal/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fotus.ru%2Fjournal%2Frabota-s-potokami-v-pitone%2F&format=xml" />
<script>var Sphere_Plugin = {"ajaxurl":"https:\/\/otus.ru\/journal\/wp-admin\/admin-ajax.php"};</script><link rel="icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-32x32.png" sizes="32x32" />
<link rel="icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-192x192.png" sizes="192x192" />
<link rel="apple-touch-icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-180x180.png" />
<meta name="msapplication-TileImage" content="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-270x270.png" />
<style type="text/css" id="wp-custom-css">
#menu-item-10406 .wpel-icon {
display: none;
}
#menu-item-10407 .wpel-icon {
display: none;
}
.otus-login-site a .wpel-icon {
display: none;
}
.menu-menju-navykov-container a .wpel-icon {
display: none;
}
.otus-login-site a
{
background: #ffd709;
border-radius: 12px;
color: #0f0f10;
font-size: 14px;
font-weight: 700;
line-height: 20px;
display: block;
text-align: center;
padding: 8px 25px;
}
.main-footer.dark {
background: linear-gradient(90deg, #a64fc5, #4f54e6);
border-color: transparent;
}
.main-footer.bold .copyright {
color: #fff;
}
.main-footer.bold .to-top i {
color: #fff;
}
.main-footer.bold .back-to-top {
color: #fff;
}
.nav__scroll {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.scrollable-menu .menu {
display: flex;
}
.nav__scroll
{
background: linear-gradient(90deg, #a64fc5, #4f54e6);
}
.scrollable-menu .menu .menu-item {
flex: 0 0 auto;
padding: 15px 15px;
}
.scrollable-menu .menu .menu-item a {
color: #fff;
}
.nav__scroll::-webkit-scrollbar{background-color:#fff;height:5px;}
.nav__scroll::-webkit-scrollbar-thumb{background-color:#dcdcdc;}
.nav__scroll::-webkit-scrollbar-track{-webkit-border-radius:0;border-radius:0;background-color:#fff;}/
body {
min-width: 320px;
}
.banner-click img {
margin: 0 auto;
display: block;
}
.banner-click {
cursor: pointer;
}
.banner-footer-area {
margin-bottom: 20px;
}
.banner-left-area {
margin-top: 40px;
} </style>
<!--Start VDZ Yandex Metrika Plugin-->
<!-- Yandex.Metrika counter --><script type="text/javascript" >(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");ym(34531570, "init", {clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true, trackHash:true, ecommerce:"dataLayer"});</script>
<noscript><div><img src="https://mc.yandex.ru/watch/34531570" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter --><!--START ADD EVENTS FROM CF7--><script type='text/javascript'>document.addEventListener( 'wpcf7submit', function( event ) {
//event.detail.contactFormId;
if(ym){
//console.log(event.detail);
ym(34531570, 'reachGoal', 'VDZ_SEND_CONTACT_FORM_7');
ym(34531570, 'params', {
page_url: window.location.href,
status: event.detail.status,
locale: event.detail.contactFormLocale,
form_id: event.detail.contactFormId,
});
}
}, false );
</script><!--END ADD EVENTS FROM CF7-->
<!--End VDZ Yandex Metrika Plugin-->
</head>
<body class="post-template-default single single-post postid-9121 single-format-standard right-sidebar lazy-normal has-lb">
<div class="main-wrap">
<header id="main-head" class="main-head head-nav-below has-search-modal simple simple-boxed">
<div class="inner inner-head" data-sticky-bar="0">
<div class="wrap cf wrap-head">
<div class="left-contain">
<span class="mobile-nav"><i class="fa fa-bars"></i></span>
<div class="title">
<a href="https://otus.ru/journal/" title="OTUS JOURNAL" rel="home" data-wpel-link="internal">
<span class="text-logo"><img src="/journal/wp-content/themes/contentberg/img/logo_site.svg" alt="OTUS JOURNAL"></span>
</a>
</div>
</div>
<div class="navigation-wrap inline">
<nav class="navigation inline simple light" data-sticky-bar="0">
<div class="menu-rubriki-container"><ul id="menu-rubriki" class="menu"><li id="menu-item-109" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-cat-1 menu-item-109"><a href="https://otus.ru/journal/category/pro-it/" data-wpel-link="internal"><span>Про IT</span></a></li>
<li id="menu-item-113" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-cat-4 menu-item-113"><a href="https://otus.ru/journal/category/polza/" data-wpel-link="internal"><span>Полезное</span></a></li>
<li id="menu-item-114" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-cat-3 menu-item-114"><a href="https://otus.ru/journal/category/lifestyle/" data-wpel-link="internal"><span>Лайфстайл</span></a></li>
<li id="menu-item-10406" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10406"><a href="https://otus.ru/catalog/courses" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right"><span>Обучение</span><span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10407" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10407"><a href="https://otus.ru/about" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right"><span>Информация</span><span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </nav>
</div>
<div class="actions">
<div class="otus-login-site">
<a href="https://otus.ru/login/" target="_blank" data-wpel-link="external" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Войти<span class="wpel-icon wpel-image wpel-icon-6"></span></a>
</div>
<a href="#" title="Search" class="search-link"><i class="fa fa-search"></i></a>
</div>
</div>
</div>
</header> <!-- .main-head -->
<div class="nav nav_disable nav_colored nav_transparent course-categories__nav nav__scroll ">
<div class="container wrap">
<div class="links inline simple light scrollable-menu">
<div class="menu-menju-navykov-container"><ul id="menu-menju-navykov" class="menu"><li id="menu-item-10413" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10413"><a href="https://otus.ru/categories/programming/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Программирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10414" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10414"><a href="https://otus.ru/categories/architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Архитектура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10415" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10415"><a href="https://otus.ru/categories/operations/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Инфраструктура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10416" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10416"><a href="https://otus.ru/categories/information-security-courses/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Безопасность<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10417" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10417"><a href="https://otus.ru/categories/data-science/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Data Science<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10418" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10418"><a href="https://otus.ru/categories/gamedev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">GameDev<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10419" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10419"><a href="https://otus.ru/categories/marketing-business/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Управление<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10420" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10420"><a href="https://otus.ru/categories/analytics/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Аналитика и анализ<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10421" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10421"><a href="https://otus.ru/categories/testing/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Тестирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </div>
</div>
</div>
<div class="main wrap">
<div class="ts-row cf">
<div class="col-8 main-content cf">
<article id="post-9121" class="the-post post-9121 post type-post status-publish format-standard has-post-thumbnail category-polza tag-python">
<header class="post-header the-post-header cf">
<div class="post-meta the-post-meta">
<span class="post-cat">
<a href="https://otus.ru/journal/category/polza/" class="category" data-wpel-link="internal">Полезное</a>
</span>
<h1 class="post-title">
Работа с потоками в Питоне
</h1>
<a href="https://otus.ru/journal/rabota-s-potokami-v-pitone/" class="date-link" data-wpel-link="internal"><time class="post-date">4 февраля, 2024</time></a>
</div>
<div class="featured">
<a href="https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-13.jpg" class="image-link" data-wpel-link="internal"><img width="770" height="515" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20770%20515%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-contentberg-main size-contentberg-main lazyload wp-post-image" alt="Работа с потоками в Питоне" title="Работа с потоками в Питоне" decoding="async" fetchpriority="high" data-srcset="https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-13-770x515.jpg 770w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-13-270x180.jpg 270w" data-src="https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-13-770x515.jpg" data-sizes="(max-width: 770px) 100vw, 770px" /> </a>
</div>
</header><!-- .post-header -->
<div class="post-content description cf entry-content content-normal">
<div id="ez-toc-container" class="ez-toc-v2_0_61 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction">
<div class="ez-toc-title-container">
<p class="ez-toc-title " >Содержание</p>
<span class="ez-toc-title-toggle"><a href="#" class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" aria-label="Toggle Table of Content"><span class="ez-toc-js-icon-con"><span class=""><span class="eztoc-hide" style="display:none;">Toggle</span><span class="ez-toc-icon-toggle-span"><svg style="fill: #999;color:#999" xmlns="http://www.w3.org/2000/svg" class="list-377408" width="20px" height="20px" viewBox="0 0 24 24" fill="none"><path d="M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z" fill="currentColor"></path></svg><svg style="fill: #999;color:#999" class="arrow-unsorted-368013" xmlns="http://www.w3.org/2000/svg" width="10px" height="10px" viewBox="0 0 24 24" version="1.2" baseProfile="tiny"><path d="M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z"/></svg></span></span></span></a></span></div>
<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-1" href="#%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B_%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D0%BF%D0%BE%D1%82%D0%BE%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8" title="Принцип работы многопоточности">Принцип работы многопоточности</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-2" href="#Threading_%E2%80%93_%D0%B4%D0%BB%D1%8F_%D1%87%D0%B5%D0%B3%D0%BE_%D0%BD%D1%83%D0%B6%D0%B5%D0%BD" title="Threading – для чего нужен">Threading – для чего нужен</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-3" href="#%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D0%B8%D0%B7%D0%BC_%E2%80%93_%D1%8D%D1%82%D0%BE%E2%80%A6" title="Параллелизм – это…">Параллелизм – это…</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-4" href="#%D0%9F%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_threading" title="Подключение threading">Подключение threading</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-5" href="#ThreadingThread" title="Threading.Thread()">Threading.Thread()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-6" href="#%D0%9D%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE_%D1%81%D0%BB%D0%BE%D0%B2_%D0%BE_%D0%B4%D0%B5%D0%BC%D0%BE%D0%BD%D0%B0%D1%85" title="Несколько слов о демонах">Несколько слов о демонах</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-7" href="#%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%B4%D0%BB%D1%8F_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B_%D1%81_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0%D0%BC%D0%B8" title="Методы для работы с потоками">Методы для работы с потоками</a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-8" href="#Start" title="Start()">Start()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-9" href="#Join" title="Join()">Join()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-10" href="#Run" title="Run()">Run()</a></li></ul></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-11" href="#%D0%9F%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BE%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0" title="Потоковая остановка">Потоковая остановка</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-12" href="#%D0%A1%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D0%B5_%D0%B3%D0%BE%D0%BD%D0%BA%D0%B8" title="Состояние гонки">Состояние гонки</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-13" href="#%D0%94%D0%BE%D1%81%D1%82%D1%83%D0%BF_%D0%BA_%D0%BE%D0%B1%D1%89%D0%B8%D0%BC_%D1%80%D0%B5%D1%81%D1%83%D1%80%D1%81%D0%B0%D0%BC_%E2%80%93_lock" title="Доступ к общим ресурсам – lock">Доступ к общим ресурсам – lock</a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-14" href="#Acquire" title="Acquire()">Acquire()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-15" href="#Release" title="Release()">Release()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-16" href="#Deadlock" title="Deadlock">Deadlock</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-17" href="#RLock" title="RLock">RLock</a></li></ul></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-18" href="#%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8_%D0%B8_%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%B0%D1%8F_%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%87%D0%B0" title="Очереди и информационная передача">Очереди и информационная передача</a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-19" href="#Qsize" title="Qsize()">Qsize()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-20" href="#Empty" title="Empty()">Empty()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-21" href="#Full" title="Full()">Full()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-22" href="#Put" title="Put()">Put()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-23" href="#Get" title="Get()">Get()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-24" href="#Task_done" title="Task_done()">Task_done()</a></li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class="ez-toc-link ez-toc-heading-25" href="#Join-2" title="Join()">Join()</a></li></ul></li></ul></nav></div>
<p>Python – достаточно простой и популярный язык программирования с объектно-ориентированной парадигмой. Он является функциональным и поддерживает огромное количество разнообразных фреймворков и библиотек. Изучать Python и его инструменты рекомендуется как новичкам в программировании, так и тем, кто уже имеет опыт в разработке программного обеспечения.</p>
<p>В процессе использования the Python предстоит решать самые разные задачи. Современные приложения проектируются так, чтобы их задачи выполнялись параллельно. Для этого в the Python имеется специальная библиотека. Она называется threading. Далее она будет рассмотрена более подробно. Также предстоит разобраться в работе многопоточности в the Python.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B_%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D0%BF%D0%BE%D1%82%D0%BE%D1%87%D0%BD%D0%BE%D1%81%D1%82%D0%B8"></span>Принцип работы многопоточности<span class="ez-toc-section-end"></span></h2>
<p>В информатике поток – это минимальная единица работы, которая запланирована для выполнения операционной системой. Он имеет такие особенности как:</p>
<ul>
<li>существование внутри процесса;</li>
<li>в одном процессе допускается несколько потоков;</li>
<li>поток в одном процессе разделяет состояние и память родительского процесса.</li>
</ul>
<p>Многопоточность – это выполнение приложения сразу в нескольких потоках, которые отвечают за выполнения ее функций одновременно.</p>
<p>Многопоточная разработка напоминает мультипроцессорную. Эти две концепции похожи между собой. Только в первом случае программное обеспечение работает с потоками, во втором – непосредственно с процессами. Разница между этими компонентами элементарна: потоки обладают общей памятью, поэтому изменения в одном из них видны в других. Процессы же используют разные области памяти.</p>
<p>В одноядерных процессорах операции из разных потоков выполняются не параллельно. Одно ядро способно выполнить только одну операцию в заданную единицу времени. Из-за того, что команды обрабатываются очень быстро, складывается впечатление, что они выполняются параллельно. Такое поведение называется псевдопараллельностью. Реально параллельная работа поддерживается только на многоядерных процессорах. Там каждое ядро способно выполнять операции независимо от других.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="Threading_%E2%80%93_%D0%B4%D0%BB%D1%8F_%D1%87%D0%B5%D0%B3%D0%BE_%D0%BD%D1%83%D0%B6%D0%B5%D0%BD"></span>Threading – для чего нужен<span class="ez-toc-section-end"></span></h2>
<p>В the Python threading представляет собой специальную библиотеку для многопоточности. Изначально в рассматриваемом языке программирования используется GIL, который является однопоточным. Все потоки, которые создаются через threading, будут функционировать внутри GIL-потока. Они обрабатываются только одним ядром.</p>
<p>Если приложению необходимо выполнять одновременно несколько задач, предстоит пользоваться упомянутой библиотекой. Также threading потребуется в следующих ситуациях:</p>
<ol>
<li>Обработка нажатия кнопки в графическом интерфейсе. Пример – через Tkinter. Если по нажатию кнопки требуется осуществлять множество действий, которые требуют времени, соответствующие операции выполняются в другом потоке. Это необходимо для устранения вероятности «подвисания» графического интерфейса.</li>
<li>Приложение функционирует одновременно с подключением нескольких устройств. Они могут быть подсоединены к разным COM-портам.</li>
<li>Загрузка файлов из сети и одновременная обработка уже загруженных элементов.</li>
</ol>
<p>Это лишь несколько наглядных примеров. Если требуется добиться работы приложения одновременно на нескольких физических ядрах процессора, рекомендуется обратить внимание на the Python библиотеку (модуль) – Multiprocessing.</p>
<p>У threading есть определенные преимуществе перед Multiprocessing:</p>
<ol>
<li>Простое использование. Начать работу с этой библиотекой достаточно легко.</li>
<li>Простота передачи данных из потока в основное приложение. Допускается использование глобальных переменных, но в этом случае программное обеспечение должно быть грамотно спроектировано: без ошибок, которые связаны с «Состоянием гонки».</li>
</ol>
<p>Если приложение будет запускаться на одноядерном компьютере или нагрузка на процессор окажется небольшой, threading – оптимальное решение для работы с потоками.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D0%B8%D0%B7%D0%BC_%E2%80%93_%D1%8D%D1%82%D0%BE%E2%80%A6"></span>Параллелизм – это…<span class="ez-toc-section-end"></span></h2>
<p>Параллелизм дает возможность нескольким вычислениям на устройстве работать одновременно в рамках единого приложения. Подобного поведения в the Python обычно удается добиться несколькими способами:</p>
<ul>
<li>через многопоточность threading;</li>
<li>при помощи multiprocessing;</li>
<li>за счет асинхронного ввода-вывода с модулем asyncio.</li>
</ul>
<p>Асинхронный ввод-вывод не относится ни к потоковым, ни к многопроцессорным. Это однопоточная однопроцессорная парадигма, которая не имеет отношения к параллельным вычислениям.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9F%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_threading"></span>Подключение threading<span class="ez-toc-section-end"></span></h2>
<p>Для начала работы с библиотекой threading в the Python не придется ничего дополнительно устанавливать. Упомянутый инструмент – это стандартный модуль. Он поставляется вместе с интерпретатором. Его потребуется всего лишь подключить через специальную команду:</p>
<p>Import threading</p>
<p>Работа с потоками возможна за счет создания экземпляров класса Thread. Чтобы сделать отдельный поток, потребуется написать экземпляр класса, а затем применить к нему метод start. Ниже можно увидеть наглядный пример:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/_8UQ-4xjzoJ_sDOquyTi7btlbWrG8aNToG7Q89VFK8eW_-4ZEaqEPSKHF_zKFb0xE1OOKzBIwSGlp2tiAVyLLD-5P_yakMOdSgRCRaP2VYGoDucXiy7_CDP7wS2Q1kVLAZnnNSToDa4Bs6FdskZe5A" alt="Работа с потоками в Питоне"/></figure>
<p>Здесь функция mydef запущена в отдельном потоке. В виде ее аргументов были переданы числа 1 и 2.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="ThreadingThread"></span>Threading.Thread()<span class="ez-toc-section-end"></span></h2>
<p>The threading.Thread() – конструкция, позволяющая создавать новые потоки путем создания экземпляров класса Thread. Ее синтаксическая форма в the Python выглядит так:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/MmljNLkTxBbBR3ovx3hkIk7gkwmeAQVDlYwnUBoS4CqXL9Y0lNST5-vo3gsAFbbt5bfweyNBGM4LucFU_JYIdcoZC0cjXeu4Bqw897HowamQdcGr0VC23tENZXOcZHG2a-eEttJBltrFlSFZ0ylDDA" alt="Работа с потоками в Питоне"/></figure>
<p>Здесь:</p>
<ol>
<li>Group. Имеет значение None. Зарезервирована данная функция для будущего расширения в процессе реализации класса ThreadGroup.</li>
<li>Target – функция, выполняемая в потоке через метод run(). Если передается значение None, ничего вызываться не будет.</li>
<li>Name – потоковое имя. По умолчанию оно принимает значение «Thread-X», где X – это десятичное число. Имя задается разработчиком самостоятельно, вручную.</li>
<li>Args – кортеж, в котором будут храниться аргументы, передаваемые в вызываемую функцию.</li>
<li>Kwargs – словарь для хранения аргументов, передаваемых в функцию.</li>
<li>Daemon – параметр, указывающий, является ли поток демоническим. По умолчанию у него установлено значение None. В этом случае свойство daemonic наследуется от текущего потока. Разработчик способен самостоятельно устанавливать значение соответствующего параметра.</li>
</ol>
<p>Daemon требует более подробного рассмотрения. Не все разработчики быстро понимают, что этот параметр собой представляет.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9D%D0%B5%D1%81%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE_%D1%81%D0%BB%D0%BE%D0%B2_%D0%BE_%D0%B4%D0%B5%D0%BC%D0%BE%D0%BD%D0%B0%D1%85"></span>Несколько слов о демонах<span class="ez-toc-section-end"></span></h2>
<p>Изучая threading в the Python, необходимо не забывать о демонах. Так называют процессы, работающие в фоновом режиме. В рассматриваемом языке программирования для него имеется более конкретное название: поток демона или демонический поток. В отличие от обычных потоков, демонический завершит работу, если закрыть приложение. Программа не станет ожидать завершения daemon-потока. При ее закрытии соответствующие потоки будут уничтожены, независимо от того, в каком именно состоянии они не находились.</p>
<p>Дэймон-потоки используются для выполнения операций, которые работают в бесконечных циклах. В других ситуациях чаще всего используются обычные потоки, которые могут задержать закрытие программы до тех пор, пока не завершат выполнение всех операций.</p>
<p>Пример использования демонического потока – когда приложение полностью перезаписывает содержимое документа, а механизм этой операции реализован в упомянутом потоке, то при неожиданном выходе из программного обеспечения данные будут утрачены.</p>
<p>Дэймон-потоки часто помещаются в функции по рисованию графических интерфейсов. Так называется бесконечная операция, которая завершается сразу после выхода из программы. Если использовать обычный поток, это помешает закрыть программное обеспечение.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9C%D0%B5%D1%82%D0%BE%D0%B4%D1%8B_%D0%B4%D0%BB%D1%8F_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B_%D1%81_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0%D0%BC%D0%B8"></span>Методы для работы с потоками<span class="ez-toc-section-end"></span></h2>
<p>В the Python для создания и управления потоками применяются разнообразные методы класса Thread. С их помощью возможно не только манипулирование, но и определение дальнейшего потокового поведения. Далее предстоит рассмотреть существующие методы, помогающие работать с многопоточностью.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Start"></span>Start()<span class="ez-toc-section-end"></span></h3>
<p>Start() – первый и самый основной метод the Python в рассматриваемом вопросе. Он применяется для того, чтобы запускать созданный ранее поток. После использования threading.Thread() появляется новый поток, но он неактивен. Чтобы запустить его в программном обеспечении, обязательно применение start-метода. Выглядит это так:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/azqe3zg4Zs7EAXJd1b3It_Atw_k4nwKMBRzh7H2Apldn0_eS_k_gFLhdp8TonpXLd0XmeqjT_zlIuaXNC3XQNeSMPTHjn3vwI4lEWXIoJfC14GxvJsY8QfHZYbc5dfvPCDp1IvfWRKcVsBad9uCH_w" alt="Работа с потоками в Питоне"/></figure>
<p>Пример выше работает так, что, пока метод start не вызван программой, в ней не будет запускаться функция myfunc.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Join"></span>Join()<span class="ez-toc-section-end"></span></h3>
<p>Join() – еще один метод в the Python. Он отвечает за блокировку выполнения потока, который его вызвал. Происходит это до тех пор, пока не завершится поток, метод которого был вызван программным обеспечением. Это значит, что если в thread1 был вызван метод thread2:thread2.join(), thread1 будет приостановлен. Он возобновит работу, как только thread2 будет завершен.</p>
<p>Соответствующий метод позволяет заставлять приложение дожидаться завершения демонического потока. Пример – при вызове метода в основном thread программа не завершается до тех пор, пока «демон» не будет выполнен.</p>
<p>Join() поддерживает аргумент timeout. По умолчанию у него значение установлено на значении None. Разработчик имеет право передать в него число с плавающей запятой. Если у аргумента установлено значение по умолчанию, значит the thread будет приостановлен, пока выполняется поток метода. При передаче в виде аргумента числового значения, метод join() получит время ожидания. Когда оно подойдет к концу, thread продолжит свое функционирование.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Run"></span>Run()<span class="ez-toc-section-end"></span></h3>
<p>Run() – метод в the Python, помогающий описывать выполняемые в thread операции. Он применяется при явном создании экземпляра класса.</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/X-AmXm7C93eWls_RiOTwvMJDevotjQIlKBWEb31uEcdkVjWwawv5Bq-624zWxMCRqFBZYipwLVA2G8lxhs0mA3QIZeOJ94eBqrh2N5gEpbqINNEuPR_mJFP6xUjtGiLY9a8RgzwKISA31vJh4tkDpQ" alt="Работа с потоками в Питоне"/></figure>
<p>Выше можно увидеть наглядный пример применения run().</p>
<p>Is_alive()</p>
<p>Метод, позволяющий проверить выполнение thread в текущий момент времени. Он часто используется вместе с join(). С помощью is_alive() удастся грамотно управлять выполнением демонических потоков, не давая им неожиданно завершать работу при закрытии программного обеспечения.</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/2k2NTO7E6eH7X1AUlQKmij7HHGTIIxSuLmgbKwgMIPLhYG7lTUhGNRe3aV3wjy9qDGdSokO4-wg_HUJH86S1BAhjteWPzb6UjL_ZM7XG79UzgwMO038J38fYoX2kR0XPU8-EAK_EavDoMDXO4I8APw" alt="Работа с потоками в Питоне"/></figure>
<p>Выше – пример практического применения is_alive() с подробными комментариями.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9F%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BE%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0"></span>Потоковая остановка<span class="ez-toc-section-end"></span></h2>
<p>Иногда рассматриваемый компонент, работающий в фоне, необходимо остановить. Пример – thread с наличием в функции run бесконечного цикла. В основном приложении требуется прекратить его функционирование. Самый простой вариант – это использование специальной переменной в the Python. Она называется stop.</p>
<p>В этом случае необходимо:</p>
<ol>
<li>Через stop. В бесконечном цикле создается постоянная проверка этой переменной. Если ее значение равняется true, цикл завершается.</li>
<li>Нельзя использовать функции, способные блокировать выполнение на длительный промежуток времени. Нужно задействовать timeout.</li>
</ol>
<p>Вот пример приложения, в котором применяется потоковая остановка:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/Aq3YQfseiMJZXAhj-BNXJ97IbUy_UZsN8mPJFPQb2FLxa9P04UgQn5OzcqyJVxOYiShtXQI2ELxXkz_gK8DqjcgiZ4Ih6C3iggVhrACPRSJv3m1Sxp6hXqYk_UvMmj6k9Rpyvr7fnJ-2O9fb7Kk3QQ" alt="Работа с потоками в Питоне"/></figure>
<p>Тут используется глобальная переменная stop. Когда необходимо остановить the thread, ей присваивается значение True. После этого останется лишь дождаться непосредственной реализации заданной «команды».</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%A1%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D0%B5_%D0%B3%D0%BE%D0%BD%D0%BA%D0%B8"></span>Состояние гонки<span class="ez-toc-section-end"></span></h2>
<p>Race condition или «состояние гонки» – ошибка, которая возникает при неправильном проектировании многопоточного программного обеспечения. Она появляется, когда несколько потоков обращаются к одной и той же информации. Пример – переменная хранит число, которое одновременно пытаются скорректировать thread1 и thread2. Это приведет к непредсказуемым результатам и даже ошибкам/сбоям.</p>
<p>Распространены ситуации, при которых один thread проверяет значения переменных на выполнение условия для совершения того или иного действия, но в процессе реализации этой операции в работу вмешивается второй thread, изменяющий значение переменной. Это влечет за собой получение конечным пользователем неправильных результатов. Вот – наглядный пример такой ситуации:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/TD1d0uvSH7CpaTJuhmnQ1An-1Ts5qSvyn_C0TMvKITOK8CJ6NGRQmeTkYEVS-TkeWHa9r6dlAlpCf6EBHhXH51E7gR0IDRAD5fEFX6V2nL_kwQPaYm5-Djkc5JmxJnYkyYDaklIuXu-BVzakUWniUQ" alt="Работа с потоками в Питоне"/></figure>
<p>Состояние гонки – ситуация, приводящая к самым разным проблемам:</p>
<ul>
<li>утечке памяти;</li>
<li>потере информации;</li>
<li>уязвимостям в безопасности запускаемого программного обеспечения;</li>
<li>взаимным потоковым блокировкам;</li>
<li>получению ошибочных (неверных) данных.</li>
</ul>
<p>Предотвратить состояние гонки помогает управление доступом к общим ресурсам. Его необходимо изучить более детально.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%94%D0%BE%D1%81%D1%82%D1%83%D0%BF_%D0%BA_%D0%BE%D0%B1%D1%89%D0%B8%D0%BC_%D1%80%D0%B5%D1%81%D1%83%D1%80%D1%81%D0%B0%D0%BC_%E2%80%93_lock"></span>Доступ к общим ресурсам – lock<span class="ez-toc-section-end"></span></h2>
<p>Для устранения состояния гонки необходимо воспользоваться блокировкой – threading.Lock(). Она не дает нескольким потокам работать с одной и той же информацией. Lock отвечает за защиту данных от одновременного доступа.</p>
<p>Threading.Lock() возвращает объект, который является своеобразной «дверью». Она будет запираться, если в комнате кто-то находится. Это значит, если потом использовал Lock (осуществлен вход в комнату), другой поток должен вынужденно находиться в ожидании отказа от «предыдущего thread» (в ожидании выхода из комнаты). Полученный объект будет обладать двумя методами – release() и acquire().</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Acquire"></span>Acquire()<span class="ez-toc-section-end"></span></h3>
<p>Acquire() – это метод, который дает возможность the thread получить блокировку. Он обладает двумя аргументами: blocking и timeout. При вызове метода с аргументом blocking = true (параметр, устанавливаемый по умолчанию) Lock блокируется до тех пор, пока он не будет разблокирован. Возвращаемое значение окажется true. Если object уже заблокирован, поток окажется приостановленным. Он будет ожидать разблокировки, после чего самостоятельно его заблокирует.</p>
<p>Если будет вызван аргумент с False, при условии, что объект Lock разблокирован, метод будет блокировать его, а затем возвращать значение true. Если Lock заблокирован, метод ничего делать не будет. В приложении просто возвращается значение False.</p>
<p>Аргумент timeout (по умолчанию -1), предусматривает возможность изменения, только если аргумент blocking имеет значение true. Если в виде параметра передается положительное значение, объект блокируется на указанный промежуток времени (в секундах) с учетом ожидания блокировки. Аргумент по умолчанию указывает методу на необходимость применения бесконечного ожидания.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Release"></span>Release()<span class="ez-toc-section-end"></span></h3>
<p>Release() – метод, который отвечает за разблокировку Lock. Интерпретатор позволит вызвать его из любого потока, а не только из того, который заблокировал упомянутый ранее объект на текущий момент.</p>
<p>The release() ничего не возвращает. Он вызывает ошибку в приложении RuntimeError, если метод будет вызван, когда Lock уже разблокирован. Ниже представлен наглядный пример использования release():</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/bU3_zcujhB6MkTzhHZDJW6F_gFaUd_Z7KT0wUwKMhy4BrgdJqZeSW6rhUabBW6DfmY1EvBh9TAt_g6iXgudhz4v11i5gkAgsgHNZoXy5OGx6ML89we928kVrFiZl0b90JoCgxv9WIAt9_hNuI3xeWg" alt="Работа с потоками в Питоне"/></figure>
<p>В примере выше:</p>
<ol>
<li>Создается Lock-объект. Он поможет безопасно считывать и корректировать информацию.</li>
<li>В виде данных, подлежащих блокировке, выступает одна переменная x.</li>
<li>После продемонстрировано безопасное изменение информации: сначала при помощи acquire требуется дождаться своей очереди к ним, после чего происходит ее корректировка. Она заключается в перезаписи значения переменной.</li>
<li>Система выводит значение в консоль.</li>
<li>Далее происходит освобождение доступа для других потоков.</li>
</ol>
<p>Если все потоки, которым потребуется доступ к данным x, предусматривают использование Lock, получится устранить ситуацию гонки.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Deadlock"></span>Deadlock<span class="ez-toc-section-end"></span></h3>
<p>При использовании the Lock появляется серьезная проблема. Она нередко приводит к полному прекращению функционирования программного обеспечения. Если вызвать acquire(), когда the Lock уже разблокирован, то thread, который вызвал acquire(), будет находиться в ожидании вызова release() потоком, заблокировавший объект.</p>
<p>Если один thread вызывает блокировку (method) несколько раз подряд, его выполнение прекращается. Это происходит до тех пор, пока поток самостоятельно не обратится к вызову release(). Это невозможно, потому что выполнение the thread приостановлено. Ситуация указывает на то, что исходное приложение попадает под бесконечную блокировку.</p>
<p>Самоблокировка – процесс, который можно предотвратить. Для этого потребуется удалить лишний вызов acquire(). Подобная операция возможна не всегда.</p>
<p>Самоблокировка происходит по разным причинам. К ним можно отнести:</p>
<ul>
<li>появление ошибок, когда Lock остается со статусом «блокировка активирована»;</li>
<li>неправильное проектирование приложения – когда одна команда вызывается другой функцией, у которой нет блокировки.</li>
</ul>
<p>При появлении проблем достаточно воспользоваться специальной конструкцией – try-finally. Вместо нее допускается использование оператора with:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/FWy6LvfCJDQ76cnra-Q8UkoDHiJtW2zvSRijasW0eJPncrNIVHBVJIt9XTRtreFk09kXJQGEYYpDyZuURr0DtbffjXx0pHE14lQK_-mvyqiimFG88H6ra6czhvZWL-weiG1zDgUIttTw9XmbJTq5Kg" alt="Работа с потоками в Питоне"/></figure>
<p>Try-finally – конструкция, с помощью которой получится удалить блокировку, даже если возникнут ошибки. Это позволяет миновать the deadblock. Вот наглядный пример реализации концепции:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/iWeI6BfVkTuPl9QQaOgFHxFQN-_x-7Roxw8428GcTNuaFETKhsh-ZSByZOBBUd--Q3AJTXPdqHN3gMVyD6Y61owGibU5S1voaUVF1MdDDzu7hIsWAGXwntQykGlftRnOP8i71-u4luFrniz1d9GmqQ" alt="Работа с потоками в Питоне"/></figure>
<p>С помощью the try-finally гарантируется, что код в finally всегда исполняется, независимо от ошибок и результатов, полученных в блоке try. В случае, когда блокировка вызвана неправильным проектированием, соответствующий прием не работает. Для исправления ситуации был создан специальный объект RLock.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="RLock"></span>RLock<span class="ez-toc-section-end"></span></h3>
<p>Если Lock заблокирован, он будет блокировать любые потоки the Python, которые попытались сделать то же самое, даже если этот thread является владельцем блокировки на текущий момент. Вот пример кода, который поможет лучше понять ситуацию:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/YQa_7fVurGTxbpHR6DU9438F1EiEIJdlaKCPVeylkAyeEstRVFJr13o1SKcrsUYbBqCf5aAkIRIARqv0sSqGFMIA76EJHr3dszazmZTQhh62lGXyEZqFtLc45IBHlFbKvxUxAHsH-822Y70KpKshnw" alt="Работа с потоками в Питоне"/></figure>
<p>Функционирование данного фрагмента кода допускается, но существует одна проблема. Она заключается в том, что в процессе вызова функции both_parts, в ней будут вызваны команды part1 и part2. Между обращением к соответствующим операциям допускается ситуация, когда какой-нибудь thread получит доступ к информации и поменяет ее. </p>
<p>Для устранения соответствующей ситуации необходимо заблокировать lock1. При переписывании программного кода в both_parts получится следующий результат:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/Bw9YzU4OrcFk4IoJsGvIhgTDZ_gHDecJ1ESSFbD3rmX0ec5UWIKLqPHLARmh1Pzn02TEzu7InGneZ5SJRuDKQkhkIrFSJL7E0f0Qh34-uuCWDuMELtd8XlhfmE4NofSeLICITMCwSSyd_XbksXWQuw" alt="Работа с потоками в Питоне"/></figure>
<p>Идея здесь простая: внешняя both_parts блокирует поток на время выполнения функции part1 part2. Каждая команда также блокирует поток для суммирования своей части объекта. The Lock не позволяет это сделать. В итоге код приводит к зависанию программного обеспечения. Это связано с тем, что для Lock не имеет значения, где в потоке был вызван acquire().</p>
<p>RLock будет блокировать поток только тогда, когда объект заблокирован другим thread. С его помощью удается полностью исключить потоковую самоблокировку.</p>
<p>Использование RLock требуется для того, чтобы управлять вложенным доступом к разделяемым объектам. Для решения возникшей проблемы с Lock в приведенном ранее примере достаточно заменить строку lock1 = threading.Lock() на lock1 = threading.RLock().</p>
<p>В процессе работы необходимо запомнить, что, хоть вызов acquire() возможен несколько раз, методу release() потребуется аналогичного количества обращений. Каждый вызов acquire() влечет за собой увеличение рекурсии на единицу. При использовании release() она уменьшается на точно такое же значение.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D0%B8_%D0%B8_%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%B0%D1%8F_%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%87%D0%B0"></span>Очереди и информационная передача<span class="ez-toc-section-end"></span></h2>
<p>Класс Queue используется для того, чтобы можно было передавать данные с помощью очередей. Он располагается в библиотеке queue, которая импортируется командой:</p>
<p>From queue import Queue.</p>
<p>Данная библиотека включает в себя все инструменты, которые пригодятся для передачи информации между потоками. Она отвечает за реализацию необходимых механизмов блокировки.</p>
<p>Класс the Queue отвечает в первую очередь за реализацию FIFO, который функционирует так: первый компонент, вошедший в очередь, первый из него выходит. Эта очередь сравнима с вертикальной полой трубой, в которую сверху бросаются различные предметы.</p>
<p>У Queue предусматривается параметр maxsize. Он способен принимать исключительно целочисленные значения. Используется для указания предельного количества элементов, допустимых для помещения в очередь. При достижении максимума добавление в очередь блокируется. Это происходит до тех пор, пока в ней не появится свободное пространство (не освободится место). Если у maxsize значение больше или равно 0, очередь бесконечна.</p>
<p>Для взаимодействия с очередями применяется Event – это объект модуля threading. Он дает возможность потоку выполнить необходимые операции при получении сигнала от другого the thread. Поток не обязательно должен останавливать свою работу на время ожидания сигнала.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Qsize"></span>Qsize()<span class="ez-toc-section-end"></span></h3>
<p>Для передачи информации и работы с очередями в the Python thread используются отдельные методы. Первый – это qsize(). Он отвечает за возврат примерного размера очереди. Здесь необходимо понимать следующее:</p>
<ul>
<li>если qsize() > 0, следующий метод get() все равно может попасть под блокировку;</li>
<li>если qsize() < maxsize, следующие put() допускает блокировку.</li>
</ul>
<p>Это не единственный метод для работы с передачей данных. Далее будут представлены другие концепции, которые применяются программистами.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Empty"></span>Empty()<span class="ez-toc-section-end"></span></h3>
<p>Empty() – метод, проверяющий очередь на факт содержания чего-либо. Если она пуста, система возвращает значение true. В противном случае – результатом станет false. Это не гарантирует того, что get() или put() не окажутся заблокированными.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Full"></span>Full()<span class="ez-toc-section-end"></span></h3>
<p>Full() отвечает за проверку заполненности очереди. Если она заполнена, возвращается true-значение, в противном случае система выдаст результат false. Как и в прошлом случае, возврат true/false не дает никаких гарантий, что put() и get() не попадут под блокировку.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Put"></span>Put()<span class="ez-toc-section-end"></span></h3>
<p>Put() – отвечает за помещение нового объекта в очередь. У него предусматривается обязательный аргумент item, а также два необязательных: block = True, timeout = None. Выглядит этот метод так:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/Z8YU63NccxbvRMVx6dTpQpqpoMOSTG1t8sAL_E-tqJDG70XT1q8pY9p7aLl5bq9Aan8R1RrrgsTo7HW3jAdZHOWH8jbW3LE81z2veKjSH9iBtRLKDHHLzkEHZTilReF6rrFL8sHX0RPama38O5W33w" alt="Работа с потоками в Питоне"/></figure>
<p>В зависимости от используемых аргументов, ожидание места в очереди ведет себя по-разному. Допускаются следующие варианты развития событий:</p>
<ol>
<li>Если параметр the block будет иметь значение True, а the timeout – None, объект, который требуется загрузить в очередь, будет бесконечно ждать свободного пространства.</li>
<li>Если the timeout > 0, ожидание свободного места длится не более указанного количества секунд. Если за этот период пространство не появилось, возбуждается исключение.</li>
<li>При the block со значением False аргумент timeout игнорируется. Элемент может быть помещен в очередь только при наличии свободного места. В противном случае система сразу генерирует исключение.</li>
</ol>
<p>Ниже – пример создания очереди в the Python с дальнейшим добавлением в нее компонента:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/FFvqgf3YVdf-83DShRNuoL1yHzR5ct9puMk0ulOUeTVdBDU3wIMfrmpliDVOor56drjfbUm_Lr5iwKBNoigBHLZcsq5tSYUhJblXmK5X4oTQOyAdd7JAV81Ds4hMTitWAYptCeHURiJpP2Akz7R_AA" alt="Работа с потоками в Питоне"/></figure>
<p>Также есть метод put(nowait). Он работает так же, как и put(item, False). С его применением осуществляется помещение элемента в очередь только при наличии места. Если оно отсутствует, приложение вызовет исключение.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Get"></span>Get()<span class="ez-toc-section-end"></span></h3>
<p>Get() – отвечает за удаление и возврат элемента из очереди. У него два необязательных аргумента – как и у put:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/NON9up4hMxfRNX3WXvlGQTM3C0JJ5R8Aj7RzLNp-XO9DmZoGPSI3z15SeBs2k-W9hpwOqAJEWqIfFhxmcH4uTS0WX-9WW04Kc6LlnisbSTZ87r_BT65AOSk1ccYPiMnks1j5EPDrqir8XDv5fjsS3Q" alt="Работа с потоками в Питоне"/></figure>
<p>Поведение также зависит от значений аргументов:</p>
<ol>
<li>При значении по умолчанию метод ожидает объект из очереди, пока он не станет доступным.</li>
<li>Если timeout – это положительное число, объект из очереди ожидается заданное время. Как только оно закончится, система выдаст исключение.</li>
<li>Если block имеет значение false – компонент возвращается, только если он является недоступным. В противном случае будет вызвано исключение. Аргумент timeout будет игнорироваться.</li>
</ol>
<p>Также существует get_nowait(). Он работает точно также, как и get(False).</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Task_done"></span>Task_done()<span class="ez-toc-section-end"></span></h3>
<p>Работает вместе с методом the join(). Он указывает, что поставленная ранее задача была выполнена. После получения каждого элемента из очереди, требуется вызвать task_done() для уменьшения счетчика задач. Если система обращается к нему больше, чем количество элементов в очереди, появляется исключение ValueError.</p>
<h3 class="wp-block-heading"><span class="ez-toc-section" id="Join-2"></span>Join()<span class="ez-toc-section-end"></span></h3>
<p>Join() – метод, отвечающий за блокировку потока до тех пор, пока все элементы очереди не будут получены и обработаны. Каждый раз, когда в очередь добавляется новый компонент, счетчик нерешенных задач увеличивается. При вызове task_done он уменьшается и показывает, что обработка компонента в очереди успешно завершена – возможен переход к следующему. При счетчике, равном нулю, блокировка с потока снимается. Ниже – наглядный пример реализации метода:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh7-us.googleusercontent.com/SDDlWIxmsFjUmAph4PCMa1TyrBBFcb8Kip_M7AcZOh_eE74eyEPt3yqYqfhGpPuegqtOBIKdBWVqxrp2O0AlUE-SAt0_dnUVwVseIc9DI3AuXaW5dcbw6Mt9ioHhdxunqBKLub8cSVUN37uGAMkEmg" alt="Работа с потоками в Питоне"/></figure>
<p>В данном the python threading примере операции осуществляются в одном потоке. Обычно один поток пишет данные в очередь, затем – ждет их обработки с помощью join(). Другой поток при получении каждого нового значения вызывает task_done.</p>
<p>Интересует <a href="https://otus.ru/lessons/python-professional/?utm_source=oj&utm_medium=affilate&utm_campaign=python" target="_blank" rel="noreferrer noopener nofollow external" data-wpel-link="external" class="wpel-icon-right">Python<span class="wpel-icon wpel-image wpel-icon-6"></span></a>? Добро пожаловать на курс в Otus!</p>
</div><!-- .post-content -->
<div class="the-post-foot cf">
<div class="tag-share cf">
<div class="post-tags"><a href="https://otus.ru/journal/tag/python/" rel="tag" data-wpel-link="internal">Python</a></div>
<div class="post-share">
<div class="post-share-icons cf">
<span class="counters">
</span>
<a href="https://www.facebook.com/sharer.php?u=https%3A%2F%2Fotus.ru%2Fjournal%2Frabota-s-potokami-v-pitone%2F" class="link facebook wpel-icon-right" target="_blank" title="Share on Facebook" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-facebook"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fotus.ru%2Fjournal%2Frabota-s-potokami-v-pitone%2F&text=%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%20%D1%81%20%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0%D0%BC%D0%B8%20%D0%B2%20%D0%9F%D0%B8%D1%82%D0%BE%D0%BD%D0%B5" class="link twitter wpel-icon-right" target="_blank" title="Share on Twitter" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-twitter"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fotus.ru%2Fjournal%2Frabota-s-potokami-v-pitone%2F" class="link linkedin wpel-icon-right" target="_blank" title="LinkedIn" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-linkedin"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fotus.ru%2Fjournal%2Frabota-s-potokami-v-pitone%2F&media=https%3A%2F%2Fotus.ru%2Fjournal%2Fwp-content%2Fuploads%2F2024%2F02%2Foj-1080x720-13.jpg&description=%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%20%D1%81%20%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0%D0%BC%D0%B8%20%D0%B2%20%D0%9F%D0%B8%D1%82%D0%BE%D0%BD%D0%B5" class="link pinterest wpel-icon-right" target="_blank" title="Pinterest" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-pinterest-p"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
</div>
</div>
</div>
</div>
<div class="post-nav">
<div class="post previous cf">
<a href="https://otus.ru/journal/znakomstvo-s-frejmvorkami/" title="Prev Post" class="nav-icon" data-wpel-link="internal">
<i class="fa fa-angle-left"></i>
</a>
<span class="content">
<a href="https://otus.ru/journal/znakomstvo-s-frejmvorkami/" class="image-link" rel="previous" data-wpel-link="internal">
<img width="150" height="106" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20150%20106%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-thumbnail size-thumbnail lazyload wp-post-image" alt="Знакомство с фреймворками" decoding="async" data-srcset="https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-12-150x106.jpg 150w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-12-300x212.jpg 300w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-12-1024x724.jpg 1024w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-12-768x543.jpg 768w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-12-1536x1086.jpg 1536w" data-src="https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-12-150x106.jpg" data-sizes="(max-width: 150px) 100vw, 150px" title="Знакомство с фреймворками" /> </a>
<div class="post-meta">
<span class="label">Prev Post</span>
<div class="post-meta post-meta-b">
<h2 class="post-title">
<a href="https://otus.ru/journal/znakomstvo-s-frejmvorkami/" data-wpel-link="internal">Знакомство с фреймворками</a>
</h2>
<div class="below">
<a href="https://otus.ru/journal/znakomstvo-s-frejmvorkami/" class="meta-item date-link" data-wpel-link="internal"><time class="post-date" datetime="2024-02-03T19:08:59+00:00">3 февраля, 2024</time></a>
<span class="meta-sep"></span>
<span class="meta-item read-time">8 Mins Read</span>
</div>
</div> </div>
</span>
</div>
<div class="post next cf">
<a href="https://otus.ru/journal/it-deyatelnost-i-it-specialisty-glavnoe/" title="Next Post" class="nav-icon" data-wpel-link="internal">
<i class="fa fa-angle-right"></i>
</a>
<span class="content">
<a href="https://otus.ru/journal/it-deyatelnost-i-it-specialisty-glavnoe/" class="image-link" rel="next" data-wpel-link="internal">
<img width="150" height="106" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20150%20106%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-thumbnail size-thumbnail lazyload wp-post-image" alt="IT-деятельность и IT-специалисты: главное" decoding="async" data-srcset="https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-14-150x106.jpg 150w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-14-300x212.jpg 300w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-14-1024x724.jpg 1024w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-14-768x543.jpg 768w, https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-14-1536x1086.jpg 1536w" data-src="https://otus.ru/journal/wp-content/uploads/2024/02/oj-1080x720-14-150x106.jpg" data-sizes="(max-width: 150px) 100vw, 150px" title="IT-деятельность и IT-специалисты: главное" /> </a>
<div class="post-meta">
<span class="label">Next Post</span>
<div class="post-meta post-meta-b">
<h2 class="post-title">
<a href="https://otus.ru/journal/it-deyatelnost-i-it-specialisty-glavnoe/" data-wpel-link="internal">IT-деятельность и IT-специалисты: главное</a>
</h2>
<div class="below">
<a href="https://otus.ru/journal/it-deyatelnost-i-it-specialisty-glavnoe/" class="meta-item date-link" data-wpel-link="internal"><time class="post-date" datetime="2024-02-04T11:22:33+00:00">4 февраля, 2024</time></a>
<span class="meta-sep"></span>
<span class="meta-item read-time">10 Mins Read</span>
</div>
</div> </div>
</span>
</div>
</div>
<section class="related-posts grid-3">
<h4 class="section-head"><span class="title">Читать ещё</span></h4>
<div class="ts-row posts cf">
<article class="post col-4">
<a href="https://otus.ru/journal/uroven-gotovnosti-cto-k-2026/" title="Уровень готовности CTO к 2026" class="image-link" data-wpel-link="internal">
<img width="270" height="180" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20270%20180%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="image lazyload wp-post-image" alt="Уровень готовности CTO к 2026" title="Уровень готовности CTO к 2026" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-270x180.jpg 270w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-770x515.jpg 770w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-370x245.jpg 370w" data-src="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-3-270x180.jpg" data-sizes="(max-width: 270px) 100vw, 270px" /> </a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/uroven-gotovnosti-cto-k-2026/" class="post-link" data-wpel-link="internal">Уровень готовности CTO к 2026</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-11-16T19:50:59+00:00">16 ноября, 2025</time>
</div>
</div>
</article >
<article class="post col-4">
<a href="https://otus.ru/journal/novye-uroki-noyabrya-tolko-top-temy-po-programmirovaniju/" title="Новые уроки ноября: только топ-темы по программированию" class="image-link" data-wpel-link="internal">
<img width="270" height="180" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20270%20180%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="image lazyload wp-post-image" alt="Новые уроки ноября: только топ-темы по программированию" title="Новые уроки ноября: только топ-темы по программированию" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-2-270x180.jpg 270w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-2-770x515.jpg 770w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-2-370x245.jpg 370w" data-src="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-2-270x180.jpg" data-sizes="(max-width: 270px) 100vw, 270px" /> </a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/novye-uroki-noyabrya-tolko-top-temy-po-programmirovaniju/" class="post-link" data-wpel-link="internal">Новые уроки ноября: только топ-темы по программированию</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-11-09T23:24:11+00:00">9 ноября, 2025</time>
</div>
</div>
</article >
<article class="post col-4">
<a href="https://otus.ru/journal/schjot-idjot-na-chasy/" title="Счёт идёт на часы" class="image-link" data-wpel-link="internal">
<img width="270" height="180" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20270%20180%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="image lazyload wp-post-image" alt="Счёт идёт на часы" title="Счёт идёт на часы" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2025/10/oj-1080x720-kopiya-7-270x180.png 270w, https://otus.ru/journal/wp-content/uploads/2025/10/oj-1080x720-kopiya-7-770x515.png 770w, https://otus.ru/journal/wp-content/uploads/2025/10/oj-1080x720-kopiya-7-370x245.png 370w" data-src="https://otus.ru/journal/wp-content/uploads/2025/10/oj-1080x720-kopiya-7-270x180.png" data-sizes="(max-width: 270px) 100vw, 270px" /> </a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/schjot-idjot-na-chasy/" class="post-link" data-wpel-link="internal">Счёт идёт на часы</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-10-30T15:04:59+00:00">30 октября, 2025</time>
</div>
</div>
</article >
</div>
</section>
</article> <!-- .the-post -->
</div>
<aside class="col-4 sidebar">
<div class="inner">
<ul>
<li id="search-2" class="widget widget_search"><h5 class="widget-title"><span>Поиск по блогу</span></h5>
<form method="get" class="search-form" action="https://otus.ru/journal/">
<label>
<span class="screen-reader-text">Search for:</span>
<input type="search" class="search-field" placeholder="Введите запрос и нажмите Enter" value="" name="s" title="Search for:" />
</label>
<button type="submit" class="search-submit"><i class="fa fa-search"></i></button>
</form>
</li>
<li id="tag_cloud-5" class="widget widget_tag_cloud"><h5 class="widget-title"><span>Метки</span></h5><div class="tagcloud"><a href="https://otus.ru/journal/tag/android-2/" class="tag-cloud-link tag-link-74 tag-link-position-1" style="font-size: 12.472222222222pt;" aria-label="Android (34 элемента)" data-wpel-link="internal">Android</a>
<a href="https://otus.ru/journal/tag/c-3/" class="tag-cloud-link tag-link-91 tag-link-position-2" style="font-size: 10.916666666667pt;" aria-label="C (23 элемента)" data-wpel-link="internal">C</a>
<a href="https://otus.ru/journal/tag/c-2/" class="tag-cloud-link tag-link-81 tag-link-position-3" style="font-size: 12.666666666667pt;" aria-label="C# (35 элементов)" data-wpel-link="internal">C#</a>
<a href="https://otus.ru/journal/tag/c/" class="tag-cloud-link tag-link-20 tag-link-position-4" style="font-size: 12.472222222222pt;" aria-label="c++ (34 элемента)" data-wpel-link="internal">c++</a>
<a href="https://otus.ru/journal/tag/computer-science/" class="tag-cloud-link tag-link-209 tag-link-position-5" style="font-size: 15.972222222222pt;" aria-label="computer science (78 элементов)" data-wpel-link="internal">computer science</a>
<a href="https://otus.ru/journal/tag/css/" class="tag-cloud-link tag-link-288 tag-link-position-6" style="font-size: 8.6805555555556pt;" aria-label="CSS (13 элементов)" data-wpel-link="internal">CSS</a>
<a href="https://otus.ru/journal/tag/data-science/" class="tag-cloud-link tag-link-151 tag-link-position-7" style="font-size: 8pt;" aria-label="Data Science (11 элементов)" data-wpel-link="internal">Data Science</a>
<a href="https://otus.ru/journal/tag/devops/" class="tag-cloud-link tag-link-98 tag-link-position-8" style="font-size: 10.138888888889pt;" aria-label="devops (19 элементов)" data-wpel-link="internal">devops</a>
<a href="https://otus.ru/journal/tag/docker/" class="tag-cloud-link tag-link-143 tag-link-position-9" style="font-size: 8.2916666666667pt;" aria-label="Docker (12 элементов)" data-wpel-link="internal">Docker</a>
<a href="https://otus.ru/journal/tag/gamedev/" class="tag-cloud-link tag-link-25 tag-link-position-10" style="font-size: 11.694444444444pt;" aria-label="gamedev (28 элементов)" data-wpel-link="internal">gamedev</a>
<a href="https://otus.ru/journal/tag/hr/" class="tag-cloud-link tag-link-103 tag-link-position-11" style="font-size: 8pt;" aria-label="hr (11 элементов)" data-wpel-link="internal">hr</a>
<a href="https://otus.ru/journal/tag/html/" class="tag-cloud-link tag-link-217 tag-link-position-12" style="font-size: 11.208333333333pt;" aria-label="HTML (25 элементов)" data-wpel-link="internal">HTML</a>
<a href="https://otus.ru/journal/tag/ios/" class="tag-cloud-link tag-link-101 tag-link-position-13" style="font-size: 8.9722222222222pt;" aria-label="iOS (14 элементов)" data-wpel-link="internal">iOS</a>
<a href="https://otus.ru/journal/tag/it/" class="tag-cloud-link tag-link-50 tag-link-position-14" style="font-size: 10.527777777778pt;" aria-label="IT (21 элемент)" data-wpel-link="internal">IT</a>
<a href="https://otus.ru/journal/tag/java/" class="tag-cloud-link tag-link-75 tag-link-position-15" style="font-size: 15.680555555556pt;" aria-label="Java (73 элемента)" data-wpel-link="internal">Java</a>
<a href="https://otus.ru/journal/tag/javascript/" class="tag-cloud-link tag-link-83 tag-link-position-16" style="font-size: 14.319444444444pt;" aria-label="JavaScript (53 элемента)" data-wpel-link="internal">JavaScript</a>
<a href="https://otus.ru/journal/tag/linux/" class="tag-cloud-link tag-link-141 tag-link-position-17" style="font-size: 11.888888888889pt;" aria-label="Linux (29 элементов)" data-wpel-link="internal">Linux</a>
<a href="https://otus.ru/journal/tag/machine-learning/" class="tag-cloud-link tag-link-167 tag-link-position-18" style="font-size: 8.6805555555556pt;" aria-label="Machine Learning (13 элементов)" data-wpel-link="internal">Machine Learning</a>
<a href="https://otus.ru/journal/tag/otus-book/" class="tag-cloud-link tag-link-261 tag-link-position-19" style="font-size: 9.9444444444444pt;" aria-label="otus book (18 элементов)" data-wpel-link="internal">otus book</a>
<a href="https://otus.ru/journal/tag/php/" class="tag-cloud-link tag-link-45 tag-link-position-20" style="font-size: 10.527777777778pt;" aria-label="PHP (21 элемент)" data-wpel-link="internal">PHP</a>
<a href="https://otus.ru/journal/tag/python/" class="tag-cloud-link tag-link-27 tag-link-position-21" style="font-size: 16.944444444444pt;" aria-label="Python (99 элементов)" data-wpel-link="internal">Python</a>
<a href="https://otus.ru/journal/tag/qa/" class="tag-cloud-link tag-link-155 tag-link-position-22" style="font-size: 11.402777777778pt;" aria-label="qa (26 элементов)" data-wpel-link="internal">qa</a>
<a href="https://otus.ru/journal/tag/sql/" class="tag-cloud-link tag-link-38 tag-link-position-23" style="font-size: 12.861111111111pt;" aria-label="SQL (37 элементов)" data-wpel-link="internal">SQL</a>
<a href="https://otus.ru/journal/tag/team-lead/" class="tag-cloud-link tag-link-364 tag-link-position-24" style="font-size: 9.9444444444444pt;" aria-label="team lead (18 элементов)" data-wpel-link="internal">team lead</a>
<a href="https://otus.ru/journal/tag/unity/" class="tag-cloud-link tag-link-24 tag-link-position-25" style="font-size: 8pt;" aria-label="unity (11 элементов)" data-wpel-link="internal">unity</a>
<a href="https://otus.ru/journal/tag/algoritmy/" class="tag-cloud-link tag-link-30 tag-link-position-26" style="font-size: 9.9444444444444pt;" aria-label="Алгоритмы (18 элементов)" data-wpel-link="internal">Алгоритмы</a>
<a href="https://otus.ru/journal/tag/bazy-dannyh/" class="tag-cloud-link tag-link-40 tag-link-position-27" style="font-size: 10.138888888889pt;" aria-label="Базы данных (19 элементов)" data-wpel-link="internal">Базы данных</a>
<a href="https://otus.ru/journal/tag/matematika/" class="tag-cloud-link tag-link-44 tag-link-position-28" style="font-size: 10.916666666667pt;" aria-label="Математика (23 элемента)" data-wpel-link="internal">Математика</a>
<a href="https://otus.ru/journal/tag/arhitektura-po/" class="tag-cloud-link tag-link-10 tag-link-position-29" style="font-size: 9.4583333333333pt;" aria-label="архитектура ПО (16 элементов)" data-wpel-link="internal">архитектура ПО</a>
<a href="https://otus.ru/journal/tag/bazy-dannyh-2/" class="tag-cloud-link tag-link-251 tag-link-position-30" style="font-size: 10.138888888889pt;" aria-label="базы данных (19 элементов)" data-wpel-link="internal">базы данных</a>
<a href="https://otus.ru/journal/tag/vebinar/" class="tag-cloud-link tag-link-201 tag-link-position-31" style="font-size: 13.930555555556pt;" aria-label="вебинар (48 элементов)" data-wpel-link="internal">вебинар</a>
<a href="https://otus.ru/journal/tag/dajdzhest/" class="tag-cloud-link tag-link-308 tag-link-position-32" style="font-size: 10.722222222222pt;" aria-label="дайджест (22 элемента)" data-wpel-link="internal">дайджест</a>
<a href="https://otus.ru/journal/tag/zapis-vebinara/" class="tag-cloud-link tag-link-226 tag-link-position-33" style="font-size: 14.902777777778pt;" aria-label="запись вебинара (61 элемент)" data-wpel-link="internal">запись вебинара</a>
<a href="https://otus.ru/journal/tag/zapis-uroka/" class="tag-cloud-link tag-link-272 tag-link-position-34" style="font-size: 16.069444444444pt;" aria-label="запись урока (80 элементов)" data-wpel-link="internal">запись урока</a>
<a href="https://otus.ru/journal/tag/informacionnaya-bezopasnost/" class="tag-cloud-link tag-link-232 tag-link-position-35" style="font-size: 10.138888888889pt;" aria-label="информационная безопасность (19 элементов)" data-wpel-link="internal">информационная безопасность</a>
<a href="https://otus.ru/journal/tag/karera-v-it/" class="tag-cloud-link tag-link-292 tag-link-position-36" style="font-size: 9.9444444444444pt;" aria-label="карьера в IT (18 элементов)" data-wpel-link="internal">карьера в IT</a>
<a href="https://otus.ru/journal/tag/podborka/" class="tag-cloud-link tag-link-7 tag-link-position-37" style="font-size: 12.666666666667pt;" aria-label="подборка (35 элементов)" data-wpel-link="internal">подборка</a>
<a href="https://otus.ru/journal/tag/podborka-statej/" class="tag-cloud-link tag-link-219 tag-link-position-38" style="font-size: 15.777777777778pt;" aria-label="подборка статей (75 элементов)" data-wpel-link="internal">подборка статей</a>
<a href="https://otus.ru/journal/tag/programmirovanie/" class="tag-cloud-link tag-link-65 tag-link-position-39" style="font-size: 22pt;" aria-label="программирование (332 элемента)" data-wpel-link="internal">программирование</a>
<a href="https://otus.ru/journal/tag/proekt/" class="tag-cloud-link tag-link-321 tag-link-position-40" style="font-size: 11.888888888889pt;" aria-label="проект (29 элементов)" data-wpel-link="internal">проект</a>
<a href="https://otus.ru/journal/tag/proektnaya-rabota/" class="tag-cloud-link tag-link-310 tag-link-position-41" style="font-size: 11.597222222222pt;" aria-label="проектная работа (27 элементов)" data-wpel-link="internal">проектная работа</a>
<a href="https://otus.ru/journal/tag/seti/" class="tag-cloud-link tag-link-181 tag-link-position-42" style="font-size: 12.958333333333pt;" aria-label="сети (38 элементов)" data-wpel-link="internal">сети</a>
<a href="https://otus.ru/journal/tag/testirovanie/" class="tag-cloud-link tag-link-69 tag-link-position-43" style="font-size: 13.930555555556pt;" aria-label="тестирование (48 элементов)" data-wpel-link="internal">тестирование</a>
<a href="https://otus.ru/journal/tag/upravlenie-komandoj/" class="tag-cloud-link tag-link-63 tag-link-position-44" style="font-size: 11.694444444444pt;" aria-label="управление командой (28 элементов)" data-wpel-link="internal">управление командой</a>
<a href="https://otus.ru/journal/tag/habr-2/" class="tag-cloud-link tag-link-203 tag-link-position-45" style="font-size: 13.930555555556pt;" aria-label="хабр (48 элементов)" data-wpel-link="internal">хабр</a></div>
</li>
</ul>
</div>
</aside>
</div> <!-- .ts-row -->
</div> <!-- .main -->
<footer class="main-footer dark bold">
<section class="lower-footer cf">
<div class="wrap">
<div class="links">
<div class="menu-menju-navykov-container"><ul id="menu-menju-navykov-1" class="menu"><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10413"><a href="https://otus.ru/categories/programming/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Программирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10414"><a href="https://otus.ru/categories/architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Архитектура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10415"><a href="https://otus.ru/categories/operations/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Инфраструктура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10416"><a href="https://otus.ru/categories/information-security-courses/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Безопасность<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10417"><a href="https://otus.ru/categories/data-science/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Data Science<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10418"><a href="https://otus.ru/categories/gamedev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">GameDev<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10419"><a href="https://otus.ru/categories/marketing-business/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Управление<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10420"><a href="https://otus.ru/categories/analytics/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Аналитика и анализ<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10421"><a href="https://otus.ru/categories/testing/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Тестирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </div>
<p class="copyright"> © 2015-2026 OTUS </p>
<div class="to-top">
<a href="#" class="back-to-top"><i class="fa fa-angle-up"></i> Top</a>
</div>
</div>
</section>
</footer>
</div> <!-- .main-wrap -->
<div class="mobile-menu-container off-canvas" id="mobile-menu">
<a href="#" class="close"><i class="fa fa-times"></i></a>
<div class="logo">
</div>
<ul class="mobile-menu"></ul>
</div>
<div class="search-modal-wrap">
<div class="search-modal-box" role="dialog" aria-modal="true">
<form method="get" class="search-form" action="https://otus.ru/journal/">
<input type="search" class="search-field" name="s" placeholder="Search..." value="" required />
<button type="submit" class="search-submit visuallyhidden">Submit</button>
<p class="message">
Type above and press <em>Enter</em> to search. Press <em>Esc</em> to cancel. </p>
</form>
</div>
</div>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/clearfy/components/comments-plus/assets/js/url-span.js" id="wbcr-comments-plus-url-span-js"></script>
<script type="text/javascript" id="ez-toc-scroll-scriptjs-js-extra">
/* <![CDATA[ */
var eztoc_smooth_local = {"scroll_offset":"30"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/js/smooth_scroll.min.js" id="ez-toc-scroll-scriptjs-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/vendor/js-cookie/js.cookie.min.js" id="ez-toc-js-cookie-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/vendor/sticky-kit/jquery.sticky-kit.min.js" id="ez-toc-jquery-sticky-kit-js"></script>
<script type="text/javascript" id="ez-toc-js-js-extra">
/* <![CDATA[ */
var ezTOC = {"smooth_scroll":"1","visibility_hide_by_default":"","scroll_offset":"30","fallbackIcon":"<span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span>"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/js/front.min.js" id="ez-toc-js-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/custom-script.js" id="custom-script-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/magnific-popup.js" id="magnific-popup-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jquery.fitvids.js" id="jquery-fitvids-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/imagesloaded.min.js" id="imagesloaded-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/object-fit-images.js" id="object-fit-images-js"></script>
<script type="text/javascript" id="contentberg-theme-js-extra">
/* <![CDATA[ */
var Bunyad = {"custom_ajax_url":"\/journal\/rabota-s-potokami-v-pitone\/"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/theme.js" id="contentberg-theme-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/theia-sticky-sidebar.js" id="theia-sticky-sidebar-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jquery.slick.js" id="jquery-slick-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jarallax.js" id="jarallax-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/masonry.min.js" id="masonry-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery.masonry.min.js" id="jquery-masonry-js"></script>
</body>
</html>
<!-- Cache served by breeze CACHE - Last modified: Mon, 09 Mar 2026 20:28:51 GMT -->