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