Учебники

Реализация потоков

В этой главе мы узнаем, как реализовать потоки в Python.

Модуль Python для реализации потоков

Потоки Python иногда называют легкими процессами, потому что потоки занимают гораздо меньше памяти, чем процессы. Потоки позволяют выполнять несколько задач одновременно. В Python у нас есть два следующих модуля, которые реализуют потоки в программе:

  • модуль <_thread>

  • модуль <threading>

модуль <_thread>

модуль <threading>

Основное различие между этими двумя модулями состоит в том, что модуль <_thread> обрабатывает поток как функцию, тогда как модуль <threading> обрабатывает каждый поток как объект и реализует его объектно-ориентированным способом. Кроме того, модуль <_thread> эффективен при низкоуровневой многопоточности и обладает меньшими возможностями, чем модуль <threading> .

модуль <_thread>

В более ранней версии Python у нас был модуль <thread>, но он долгое время считался устаревшим. Пользователям рекомендуется использовать модуль <threading> . Поэтому в Python 3 модуль «поток» больше не доступен. Он был переименован в « <_thread> » для обратной несовместимости в Python3.

Чтобы создать новый поток с помощью модуля <_thread> , нам нужно вызвать его метод start_new_thread . Работу этого метода можно понять с помощью следующего синтаксиса —

_thread.start_new_thread ( function, args[, kwargs] )

Здесь —

  • args это кортеж аргументов

  • kwargs — необязательный словарь аргументов ключевых слов

args это кортеж аргументов

kwargs — необязательный словарь аргументов ключевых слов

Если мы хотим вызвать функцию без передачи аргумента, нам нужно использовать пустой аргумент в аргументах .

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

пример

Ниже приведен пример создания нового потока с использованием модуля <_thread> . Мы используем метод start_new_thread () здесь.

import _thread
import time

def print_time( threadName, delay):
   count = 0
   while count < 5:
      time.sleep(delay)
      count += 1
      print ("%s: %s" % ( threadName, time.ctime(time.time()) ))

try:
   _thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   _thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print ("Error: unable to start thread")
while 1:
   pass

Выход

Следующий вывод поможет нам понять создание новых потоков с помощью модуля <_thread> .

Thread-1: Mon Apr 23 10:03:33 2018
Thread-2: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:35 2018
Thread-1: Mon Apr 23 10:03:37 2018
Thread-2: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:39 2018
Thread-1: Mon Apr 23 10:03:41 2018
Thread-2: Mon Apr 23 10:03:43 2018
Thread-2: Mon Apr 23 10:03:47 2018
Thread-2: Mon Apr 23 10:03:51 2018

модуль <threading>

Модуль <threading> реализуется объектно-ориентированным способом и обрабатывает каждый поток как объект. Следовательно, он обеспечивает гораздо более мощную высокоуровневую поддержку потоков, чем модуль <_thread>. Этот модуль включен в Python 2.4.

Дополнительные методы в модуле <threading>

Модуль <threading> включает в себя все методы модуля <_thread>, но также предоставляет дополнительные методы. Дополнительные методы заключаются в следующем —

  • threading.activeCount () — этот метод возвращает количество активных объектов потока

  • threading.currentThread () — Этот метод возвращает количество объектов потока в элементе управления потоком вызывающей стороны.

  • threading.enumerate () — этот метод возвращает список всех объектов потока, которые в данный момент активны.

  • Для реализации многопоточности модуль <threading> имеет класс Thread, который предоставляет следующие методы:

    • run () — Метод run () является точкой входа для потока.

    • start () — метод start () запускает поток, вызывая метод run.

    • join ([время]) — join () ожидает завершения потоков.

    • isAlive () — метод isAlive () проверяет, выполняется ли еще поток.

    • getName () — Метод getName () возвращает имя потока.

    • setName () — Метод setName () устанавливает имя потока.

threading.activeCount () — этот метод возвращает количество активных объектов потока

threading.currentThread () — Этот метод возвращает количество объектов потока в элементе управления потоком вызывающей стороны.

threading.enumerate () — этот метод возвращает список всех объектов потока, которые в данный момент активны.

Для реализации многопоточности модуль <threading> имеет класс Thread, который предоставляет следующие методы:

run () — Метод run () является точкой входа для потока.

start () — метод start () запускает поток, вызывая метод run.

join ([время]) — join () ожидает завершения потоков.

isAlive () — метод isAlive () проверяет, выполняется ли еще поток.

getName () — Метод getName () возвращает имя потока.

setName () — Метод setName () устанавливает имя потока.

Как создавать темы, используя модуль <threading>?

В этом разделе мы узнаем, как создавать потоки с помощью модуля <threading> . Выполните следующие шаги, чтобы создать новую тему, используя модуль <threading> —

  • Шаг 1 — На этом шаге нам нужно определить новый подкласс класса Thread .

  • Шаг 2 — Затем для добавления дополнительных аргументов нам нужно переопределить метод __init __ (self [, args]) .

  • Шаг 3 — На этом шаге нам нужно переопределить метод run (self [, args]), чтобы реализовать то, что поток должен делать при запуске.

  • Теперь, после создания нового подкласса Thread , мы можем создать его экземпляр и затем запустить новый поток, вызвав start () , который, в свою очередь, вызывает метод run () .

Шаг 1 — На этом шаге нам нужно определить новый подкласс класса Thread .

Шаг 2 — Затем для добавления дополнительных аргументов нам нужно переопределить метод __init __ (self [, args]) .

Шаг 3 — На этом шаге нам нужно переопределить метод run (self [, args]), чтобы реализовать то, что поток должен делать при запуске.

Теперь, после создания нового подкласса Thread , мы можем создать его экземпляр и затем запустить новый поток, вызвав start () , который, в свою очередь, вызывает метод run () .

пример

Рассмотрим этот пример, чтобы узнать, как создать новый поток с помощью модуля <threading> .

import threading
import time
exitFlag = 0

class myThread (threading.Thread):
   def __init__(self, threadID, name, counter):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.counter = counter
   def run(self):
      print ("Starting " + self.name)
      print_time(self.name, self.counter, 5)
      print ("Exiting " + self.name)
def print_time(threadName, delay, counter):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print ("%s: %s" % (threadName, time.ctime(time.time())))
      counter -= 1

thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("Exiting Main Thread")
Starting Thread-1
Starting Thread-2

Выход

Теперь рассмотрим следующий вывод —

Thread-1: Mon Apr 23 10:52:09 2018
Thread-1: Mon Apr 23 10:52:10 2018
Thread-2: Mon Apr 23 10:52:10 2018
Thread-1: Mon Apr 23 10:52:11 2018
Thread-1: Mon Apr 23 10:52:12 2018
Thread-2: Mon Apr 23 10:52:12 2018
Thread-1: Mon Apr 23 10:52:13 2018
Exiting Thread-1
Thread-2: Mon Apr 23 10:52:14 2018
Thread-2: Mon Apr 23 10:52:16 2018
Thread-2: Mon Apr 23 10:52:18 2018
Exiting Thread-2
Exiting Main Thread

Программа Python для различных состояний потоков

Существует пять состояний потока — новое, работоспособное, работающее, ожидающее и мертвое. Среди этих пяти из этих пяти мы сосредоточимся в основном на трех состояниях — бегущем, ожидающем и мертвом. Поток получает свои ресурсы в рабочем состоянии, ждет ресурсов в состоянии ожидания; окончательный выпуск ресурса, если исполняемый и полученный находится в мертвом состоянии.

Следующая программа на Python с помощью методов start (), sleep () и join () покажет, как поток вошел в состояние выполнения, ожидания и ожидания соответственно.

Шаг 1 — Импортируйте необходимые модули, <threading> и <time>

import threading
import time

Шаг 2 — Определите функцию, которая будет вызываться при создании потока.

def thread_states():
   print("Thread entered in running state")

Шаг 3 — Мы используем метод времени sleep () модуля, чтобы заставить наш поток ждать, скажем, 2 секунды.

time.sleep(2)

Шаг 4 — Теперь мы создаем поток с именем T1, который принимает аргумент функции, определенной выше.

T1 = threading.Thread(target=thread_states)

Шаг 5 — Теперь с помощью функции start () мы можем запустить наш поток. Он выдаст сообщение, которое было установлено нами при определении функции.

T1.start()
Thread entered in running state

Шаг 6 — Теперь, наконец, мы можем завершить поток с помощью метода join () после того, как он завершит свое выполнение.

T1.join()

Начиная поток в Python

В python мы можем запустить новый поток различными способами, но самый простой из них — определить его как одну функцию. После определения функции мы можем передать это как цель для нового объекта Threading.Thread и так далее. Выполните следующий код Python, чтобы понять, как работает функция —

import threading
import time
import random
def Thread_execution(i):
   print("Execution of Thread {} started\n".format(i))
   sleepTime = random.randint(1,4)
   time.sleep(sleepTime)
   print("Execution of Thread {} finished".format(i))
for i in range(4):
   thread = threading.Thread(target=Thread_execution, args=(i,))
   thread.start()
   print("Active Threads:" , threading.enumerate())

Выход

Execution of Thread 0 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>]

Execution of Thread 1 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>]

Execution of Thread 2 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>]

Execution of Thread 3 started
Active Threads:
   [<_MainThread(MainThread, started 6040)>,
      <HistorySavingThread(IPythonHistorySavingThread, started 5968)>,
      <Thread(Thread-3576, started 3932)>,
      <Thread(Thread-3577, started 3080)>,
      <Thread(Thread-3578, started 2268)>,
      <Thread(Thread-3579, started 4520)>]
Execution of Thread 0 finished
Execution of Thread 1 finished
Execution of Thread 2 finished
Execution of Thread 3 finished

Демонические потоки в Python

Перед реализацией потоков демона в Python нам нужно знать о потоках демона и их использовании. С точки зрения вычислений, демон — это фоновый процесс, который обрабатывает запросы на различные сервисы, такие как отправка данных, передача файлов и т. Д. Он будет бездействующим, если он больше не требуется. То же самое можно сделать и с помощью потоков, не являющихся демонами. Однако в этом случае основной поток должен отслеживать потоки, не являющиеся демонами, вручную. С другой стороны, если мы используем потоки демона, основной поток может полностью забыть об этом, и он будет убит при выходе из основного потока. Еще один важный момент, связанный с потоками демонов, заключается в том, что мы можем использовать их только для несущественных задач, которые не повлияют на нас, если они не завершатся или будут уничтожены между ними. Ниже приведена реализация потоков демонов в python —

import threading
import time

def nondaemonThread():
   print("starting my thread")
   time.sleep(8)
   print("ending my thread")
def daemonThread():
   while True:
   print("Hello")
   time.sleep(2)
if __name__ == '__main__':
   nondaemonThread = threading.Thread(target = nondaemonThread)
   daemonThread = threading.Thread(target = daemonThread)
   daemonThread.setDaemon(True)
   daemonThread.start()
   nondaemonThread.start()

В приведенном выше коде есть две функции, а именно: > nondaemonThread () и > daemonThread () . Первая функция печатает свое состояние и спит через 8 секунд, в то время как функция deamonThread () печатает Hello через каждые 2 секунды бесконечно. Мы можем понять разницу между не-демонами и потоками демонов с помощью следующего вывода: