Запуск декількох потоків аналогічний запуску декількох програм, але з декількома перевагами:
- Кілька потоків всередині одного процесу займають один простір даних з головним потоком і завдяки цьому їм набагато легше взаємодіяти та обмінюватися даними між собою, ніж якби вони були окремими процесами;
- Потоки іноді ще називають "легкими" процесами, оскільки їм не потрібно багато пам'яті;
- Потік, має початок, послідовність виконання та закінчення. Він має покажчик, який відстежує де в його контексті він працює;
- Він може бути перерваний;
- Він може бути тимчасово призупиненим, поки інші потоки працюють - така властивість називається поступання.
Початок нового потоку
Для того щоб викликати потік, потрібно викликати метод, який доступний в модулі Thread:
`**thread.start_new_thread( function, args[, kwargs] )**`
Саме виклик цього методу дозволяє швидко та ефективно створювати нові потоки. Виклик методу повертається негайно, починається "дитячий" потік і викликається функція з минулим списком аргументів. Коли функція повертається, потік завершується. Тут аргументи подані у вигляді списку аргументів. Використовувати пустий список, означає викликати функції без аргументів.
Приклад:
#!/usr/bin/python
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-1: Thu Jan 22 15:42:17 2009
Thread-1: Thu Jan 22 15:42:19 2009
Thread-2: Thu Jan 22 15:42:19 2009
Thread-1: Thu Jan 22 15:42:21 2009
Thread-2: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:25 2009
Thread-2: Thu Jan 22 15:42:27 2009
Thread-2: Thu Jan 22 15:42:31 2009
Thread-2: Thu Jan 22 15:42:35 2009
Хоч це і дуже ефективно для низькорівневих потоків, але потоковий модуль дуже обмежений в порівнянні з новими потоковими модулями.
Потоковий модуль
Більш новий потоковий модуль включений до складу Python 2.4 і він надає набагато потужнішу підтримку потоків високого рівня, ніж той модуль, який ми розглядали у попередньому розділі. Цей модуль включає все, що було у старому модулі і додає деякі додаткові методи:
-
threading.activeCount()
: Повертає кількість об'єктів потоку, які активні; -
threading.currentThread()
: Повертає кількість об'єктів потоку у викликаних thread control; - **
threading.enumerate()
:**Повертає список кількості потоків, які на даний момент активні.
На додаток до методів, модуль має клас Thread, який як ви здогадалися реалізує самі потоки. Клас має такі методи:
-
run()
: метод run(), є методом початку потоку; -
**start()**
: є методом запуску потоку після виклику методу run(); -
join([time])
: чекає закінчення виконання потоку; -
isAlive()
: перевіряє чи виконується потік; -
getName()
: повертає ім'я потоку; -
setName()
: встановлює ім'я потоку.
Створення потоку використовуючи Threading Module
Для реалізації нового потоку за допомогою Threading Module, вам потрібно виконати наступне:
- Визначити новий підклас класу Thread;
- Перегрузити метод
**__init__(self[,args])**
, для додавання нових аргументів; - Тоді, перевизначити метод
**Run(self [, args])**
для того, щоб визначити, що потік повинен робити, коли стартує; - Після того як ви створили новий підклас потоку, ви можете створити його екземпляр, а потім почати запустити потік, викликавши метод
**start()**
.
Приклад:
#!/usr/bin/python
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:
thread.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()
print "Exiting Main Thread"
Результат:
Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Thu Mar 21 09:10:03 2013
Thread-1: Thu Mar 21 09:10:04 2013
Thread-2: Thu Mar 21 09:10:04 2013
Thread-1: Thu Mar 21 09:10:05 2013
Thread-1: Thu Mar 21 09:10:06 2013
Thread-2: Thu Mar 21 09:10:06 2013
Thread-1: Thu Mar 21 09:10:07 2013
Exiting Thread-1
Thread-2: Thu Mar 21 09:10:08 2013
Thread-2: Thu Mar 21 09:10:10 2013
Thread-2: Thu Mar 21 09:10:12 2013
Exiting Thread-2
Синхронізація потоків
В Python потоковий модуль включає в себе простий у використанні механізм блокування, за допомогою якого можна синхронізувати потоки. Новий замок(Lock) можна створити викликавши метод **Lock()**
.
Необов'язковий параметр блокування дозволяє контролювати, чи буде потік чекати, щоб отримати блокування. Якщо на блокуванні встановлено 0, то потік безпосередньо буде повертатися зі значенням 0. Якщо встановлено значення 1, то потік буде заблокований і чекатиме звільнення блокування.
Метод **release()**
нового об'єкта блокування, буде використвовуватись для зняття блокування, коли воно не потрібно.
Приклад:
#!/usr/bin/python
import threading
import time
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
# Отримуємо замок для синхронізації потоків
threadLock.acquire()
print_time(self.name, self.counter, 3)
# Відкритий замок для реалізування наступного потоку
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print "%s: %s" % (threadName, time.ctime(time.time()))
counter -= 1
threadLock = threading.Lock()
threads = []
# Створюємо нові потоки
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Запускаємо нові потоки
thread1.start()
thread2.start()
# Додаємо потоки до списку потоків
threads.append(thread1)
threads.append(thread2)
# Чекємо завершення всіх потоків
for t in threads:
t.join()
print "Exiting Main Thread"
Результат:
Starting Thread-1
Starting Thread-2
Thread-1: Thu Mar 21 09:11:28 2013
Thread-1: Thu Mar 21 09:11:29 2013
Thread-1: Thu Mar 21 09:11:30 2013
Thread-2: Thu Mar 21 09:11:32 2013
Thread-2: Thu Mar 21 09:11:34 2013
Thread-2: Thu Mar 21 09:11:36 2013
Exiting Main Thread
Багатопотокова пріоритетна черга
Модуль Queue дозволяє створити новий об'єкт черги, який може містити певну кількість пунктів. Існують наступні способи управління чергою:
- **
get()
:**видаляє і повертає елементи з черги; -
put()
: додає елементи в чергу; -
qsize()
: повертає кількість елементів, які в даний час в черзі; -
empty()
: повертає True, якщо черга порожня, в іншому випадку - False; - **
full()
:**повертає True, якщо черга заповнена, в в іншому випадку - False.
Приклад:
#!/usr/bin/python
import Queue
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
def run(self):
print "Starting " + self.name
process_data(self.name, self.q)
print "Exiting " + self.name
def process_data(threadName, q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print "%s processing %s" % (threadName, data)
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1
# Створюємо нові потоки
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
# Заповнюємо чергу
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
# Чекаємо порожню чергу
while not workQueue.empty():
pass
# "Нагадуємо" потокам про час закінчення
exitFlag = 1
# Чекаємо завершення всіх потоків
for t in threads:
t.join()
print "Exiting Main Thread"
Результат:
Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 processing One
Thread-2 processing Two
Thread-3 processing Three
Thread-1 processing Four
Thread-2 processing Five
Exiting Thread-3
Exiting Thread-1
Exiting Thread-2
Exiting Main Thread
Ще немає коментарів