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

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

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

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

  • <_thread>module

  • <threading>module

Основное различие между этими двумя модулями заключается в том, что <_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.

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

пример

Ниже приведен пример создания нового потока с использованием <_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([time]) - join () ожидает завершения потоков.

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

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

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

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

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

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

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

  • Step 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 () покажет, как поток вошел в состояние выполнения, ожидания и мертвого состояния соответственно.

Step 1 - Импортировать необходимые модули, <поток> и <время>

import threading
import time

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

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

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

time.sleep(2)

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

T1 = threading.Thread(target=thread_states)

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

T1.start()
Thread entered in running state

Step 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 секунды до бесконечности. Мы можем понять разницу между потоками nondaemon и daemon с помощью следующего вывода:

Hello

starting my thread
Hello
Hello
Hello
Hello
ending my thread
Hello
Hello
Hello
Hello
Hello