Кроме модуля _thread, разобранного Нами в прошлой записи, есть и другой "источник" потоков.
Модуль threading
На самом деле, модули, позволяющие запускать параллельные потоки и даже процессы, очень похожи. Убедиться в этом можно на следующем примере:
| Python | 1
2
3
4
5
6
7
8
9
10
| from threading import Thread
from time import sleep
def fu():
sleep(5)
print('Done')
th=Thread(target=fu,args=())
th.start()
sleep(2)
print('Hello,world!')
input() |
|
Похоже на пример из прошлой записи. Напомню, что тот скрипт через две секунды после запуска печатал "Hello,world!", а ещё через три выдавал надпись "Done". Этот делает то же самое. Налицо здесь только одно отличие: работая с модулем _thread, Мы использовали функцию(start_new_thread()), а здесь Мы присваиваем переменной th экземпляр класса Thread().
С блокировками потоков ситуация аналогична, даже проще:
| Python | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| import threading
from time import sleep
l=threading.Lock()
def hel():
while True:
if not l.locked():
sleep(1)
print('Hello')
def by():
while True:
sleep(1)
print('By')
th1=threading.Thread(target=hel,args=())
th2=threading.Thread(target=by,args=())
th1.start()
sleep(0.5)
th2.start()
sleep(3)
l.acquire()
sleep(3.5)
l.release()
input() |
|
Как видите, блокировки разных thread-модулей отличаются только названием. Даже методы классов имеют одинаковые имена:
| Python | 1
2
| l.acquire()#заблокировать выполнение потока
l.release()#разблокировать поток |
|
Но есть один очень полезный метод, который в _thread не наблюдается.
| Python | 1
2
3
4
5
6
7
8
9
10
11
| from threading import Thread
from time import sleep
def fu():
sleep(3)
print('Hello,world!')
th=Thread(target=fu,args=())
th.start()
th.join()
sleep(1)
print('Done')
input() |
|
Следовало ожидать, что первым делом появится надпись "Done", так как время её появления - 1 секунда. Но на деле оказывается, что сначала выскочил старый добрый Hello,world!. Отсюда можно сделать вывод, что метод join() заставляет основной поток ждать завершения выполнения функции, запущенной параллельно. Конечно, работая с модулем _thread, можно добиться такого же эффекта, используя блокировки, но к чему лишнее копошение.
До сих пор Мы использовали функцию sleep() для организации задержек. Не могу сказать, что это неправильно или не практично, но модуль threading вмещает в себя ещё один интересный класс, который может заменить собой sleep().
| Python | 1
2
3
4
5
6
7
8
9
10
11
| import threading
from time import sleep
def fun():
for i in range(1,6):
sleep(0.5)
print('Hello,world!')
tim=threading._Timer(3,fun,args=())
tim.start()
sleep(2)
print('Go!')
input() |
|
В данном скрипте Мы использовали класс _Timer(), который является наследником Thread().
_Timer представляет собой тот же самый параллельный поток, с теми же методами, но вот запускается он через определённый промежуток времени, тот, который Вы указываете первым при конструировании потока (threading._Timer(3,fun,args=())). Дальше, как несложно догадаться, передаётся функция и аргументы, которые ей потребуются. Таким образом, после команды tim.start() с трёх-секундной задержкой начинается выполнение параллельного потока.
Вы так же можете использовать метод join() для организации ожидания завершения потока запущенного _Timer'ом. В общем, всё так же, как и с классом Thread(). Но _Timer() имеет ещё один, дополнительный метод, который позволяет предотвратить запуск параллельного потока. Это метод cancel(). Учтите, что он предотвращает выполнение потока только в том случае, если таймер ещё идёт. А вот если функция стартанула, cancel() Вам уже не поможет. Пример:
| Python | 1
2
3
4
5
6
7
8
9
10
11
12
| import threading
from time import sleep
def fun():
for i in range(1,6):
sleep(0.5)
print('Hello,world!')
tim=threading._Timer(1,fun,args=())
tim.start()
sleep(2)
tim.cancel()
print('Done')
input() |
|
Появление надписи "Done" знаменует выполнение метода cancel()(две секунды после старта скрипта). Но выполнение потока началось секундой раньше, а это значит, что функция будет выполняться до конца(в Нашем случае она продолжает выводить 'Hello,world!'). Но достаточно в строке tim=threading._Timer(1,fun,args=()) цифру "1" заменить на "3" и запуск потока будет предотвращён..
Возможно, Вы заметили, что функцию sleep() Мы, всё-таки, использовали. Она помогает создать наглядный пример. Я, в свою очередь, стараюсь писать скрипты как можно проще, чтобы Вам не приходилось сидеть над десятками строк кода и разбираться, в чём суть скрипта и где же в нём запускаются параллельные потоки.
|