В этой главе мы узнаем, как реализовать потоки в 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 () — этот метод возвращает список всех объектов потока, которые в данный момент активны.
-
run () — Метод run () является точкой входа для потока.
-
start () — метод start () запускает поток, вызывая метод run.
-
join ([время]) — join () ожидает завершения потоков.
-
isAlive () — метод isAlive () проверяет, выполняется ли еще поток.
-
getName () — Метод getName () возвращает имя потока.
-
setName () — Метод setName () устанавливает имя потока.
Для реализации многопоточности модуль <threading> имеет класс Thread, который предоставляет следующие методы:
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 секунды бесконечно. Мы можем понять разницу между не-демонами и потоками демонов с помощью следующего вывода: