№34 Потоки и многопоточность / для начинающих

Предыдущий урок: Приватные переменные

Модуль threading в Python используется для реализации многопоточности в программах. В этом материале разберемся с Thread и разными функциями этого модуля.

Что такое поток?

В информатике поток — это минимальная единица работы, запланированная для выполнения операционной системой.

О потоках нужно знать следующее:

  • Они существуют внутри процесса;
  • В одном процессе может быть несколько потоков;
  • Потоки в одном процессе разделяют состояние и память родительского процесса.

Модуль threading в Python можно представить таким простым примером:


import time
from threading import Thread

def sleepMe(i):
print("Поток %i засыпает на 5 секунд.\n" % i)
time.sleep(5)
print("Поток %i сейчас проснулся.\n" % i)

for i in range(10):
th = Thread(target=sleepMe, args=(i, ))
th.start()

После запуска скрипта вывод будет следующий:

Поток 0 засыпает на 5 секунд.
Поток 3 засыпает на 5 секунд.
Поток 1 засыпает на 5 секунд.
Поток 4 засыпает на 5 секунд.
Поток 2 засыпает на 5 секунд.
Поток 5 засыпает на 5 секунд.
Поток 6 засыпает на 5 секунд.
Поток 7 засыпает на 5 секунд.
Поток 8 засыпает на 5 секунд.
Поток 9 засыпает на 5 секунд.

Поток 0 сейчас проснулся.

Поток 3 сейчас проснулся.
Поток 1 сейчас проснулся.

Поток 4 сейчас проснулся.

Поток 2 сейчас проснулся.
Поток 5 сейчас проснулся.

Поток 6 сейчас проснулся.
Поток 7 сейчас проснулся.

Поток 8 сейчас проснулся.

Поток 9 сейчас проснулся.

У вас он может отличаться, потому что у параллельных потоков нет определенного порядка.

Функции threading в Python

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

threading.active_count()

Эта функция возвращает количество исполняемых на текущий момент потоков. Изменим последнюю программу, чтобы она выглядела вот так:


import time
import threading
from threading import Thread

def sleepMe(i):
print("Поток %i засыпает на 5 секунд." % i)
time.sleep(5)
print("Поток %i сейчас проснулся." % i)

for i in range(10):
th = Thread(target=sleepMe, args=(i, ))
th.start()
print("Запущено потоков: %i." % threading.active_count())

Теперь в выводе будет показываться количество активных на текущий момент потоков:

Поток 0 засыпает на 5 секунд.Запущено потоков: 3.
Запущено потоков: 4.Поток 1 засыпает на 5 секунд.
Запущено потоков: 5.Поток 2 засыпает на 5 секунд.
Поток 3 засыпает на 5 секунд.Запущено потоков: 6.
Запущено потоков: 7.Поток 4 засыпает на 5 секунд.
Поток 5 засыпает на 5 секунд.Запущено потоков: 8.
Поток 6 засыпает на 5 секунд.Запущено потоков: 9.
Запущено потоков: 10.Поток 7 засыпает на 5 секунд.
Поток 8 засыпает на 5 секунд.Запущено потоков: 11.
Поток 9 засыпает на 5 секунд.Запущено потоков: 12.

Поток 0 сейчас проснулся.
Поток 1 сейчас проснулся.
Поток 2 сейчас проснулся.
Поток 3 сейчас проснулся.
Поток 4 сейчас проснулся.
Поток 5 сейчас проснулся.
Поток 6 сейчас проснулся.
Поток 7 сейчас проснулся.
Поток 8 сейчас проснулся.
Поток 9 сейчас проснулся.

Также обратите внимание, что после запуска всех потоков счетчик показывает число 11, а не 10. Причина в том, что основной поток также учитывается наравне с 10 остальными.

threading.current_thread()

Эта функция возвращает исполняемый прямо сейчас поток. С ее помощью можно выполнять определенные действия с ним. Поменяем все тот же скрипт:


import time
import threading
from threading import Thread

def sleepMe(i):
print("Поток %s засыпает на 5 секунд.\n" % threading.current_thread())
time.sleep(5)
print("Поток %s сейчас проснулся." % threading.current_thread())

# Cоздаем только четыре потока
for i in range(10):
th = Thread(target=sleepMe, args=(i, ))
th.start()

Теперь вывод будет таким:

Поток <Thread(Thread-4, started 13324)> засыпает на 5 секунд.
Поток <Thread(Thread-1, started 15748)> засыпает на 5 секунд.
Поток <Thread(Thread-5, started 12164)> засыпает на 5 секунд.
Поток <Thread(Thread-2, started 15972)> засыпает на 5 секунд.
Поток <Thread(Thread-6, started 13540)> засыпает на 5 секунд.
Поток <Thread(Thread-3, started 14396)> засыпает на 5 секунд.
Поток <Thread(Thread-7, started 15620)> засыпает на 5 секунд.
Поток <Thread(Thread-8, started 7644)> засыпает на 5 секунд.
Поток <Thread(Thread-9, started 15424)> засыпает на 5 секунд.
Поток <Thread(Thread-10, started 15852)> засыпает на 5 секунд.

Поток <Thread(Thread-4, started 13324)> сейчас проснулся.
Поток <Thread(Thread-1, started 15748)> сейчас проснулся.
Поток <Thread(Thread-5, started 12164)> сейчас проснулся.Поток <Thread(Thread-2, started 15972)> сейчас проснулся.
Поток <Thread(Thread-6, started 13540)> сейчас проснулся.
Поток <Thread(Thread-3, started 14396)> сейчас проснулся.Поток <Thread(Thread-7, started 15620)> сейчас проснулся.
Поток <Thread(Thread-8, started 7644)> сейчас проснулся.Поток <Thread(Thread-9, started 15424)> сейчас проснулся.
Поток <Thread(Thread-10, started 15852)> сейчас проснулся.

threading.main_thread()

Эта функция возвращает основной поток программы. Именно из него создаются новые потоки.

import threading
print(threading.main_thread())

Запустим:

<_MainThread(MainThread, started 10476)>

threading.enumerate()

Эта функция возвращает список всех активных потоков. Пользоваться ею проще простого:


import threading
for thread in threading.enumerate():
print("Имя потока %s." % thread.getName())

Запустим скрипт:

Имя потока MainThread.
Имя потока SockThread.

Сейчас работает только 2 потока, поэтому в выводе есть только они.

threading.Timer()

Эта функция модуля threading используется для создания нового потока и указания времени, через которое он должен запуститься. После запуска поток вызывает определенную функцию. Разберем на примере:


import threading

def delayed():
print("Вывод через 5 секунд!")

thread = threading.Timer(5, delayed)
thread.start()

Запустим скрипт:

Вывод через 5 секунд!

Многопоточность в Python

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

Далее: Assert