Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Python

Многопоточное программирование в Python: эффективные техники параллелизма

Преимущества потоков

Запуск нескольких потоков похож на запуск нескольких разных программ одновременно, но с преимуществами:

У потока есть начало, последовательность выполнения и конец. У него есть указатель инструкций, отслеживающий, где в своем контексте он сейчас выполняется.

Запуск нового потока (модуль thread)

Для порождения другого потока нужно вызвать метод из модуля thread:

thread.start_new_thread(function, args[, kwargs])

Этот вызов обеспечивает быстрый и эффективный способ создания новых потоков в Linux и Windows.

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

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

Хотя модуль thread эффективен для низкоуровневого трединга, он очень ограничен по сравнению с более новым модулем threading.

Модуль threading

Новый модуль threading, включенный в Python 2.4, предоставляет гораздо более мощную высокоуровневую поддержку потоков, чем модуль thread.

Модуль threading раскрывает все методы модуля thread и предоставляет дополнительные:

Помимо методов, модуль threading имеет класс Thread, реализующий потоки. Методы класса Thread:

Создание потока с помощью модуля threading

Для реализации нового потока с использованием модуля threading нужно:

После создания подкласса Thread можно создать его экземпляр и запустить новый поток, вызвав start(), который в свою очередь вызывает run().

Пример

#!/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, 5, self.counter)
        print("Exiting " + self.name)

def print_time(threadName, counter, delay):
    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()
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

Синхронизация потоков

Модуль threading включает простой в реализации механизм блокировки для синхронизации потоков. Новая блокировка создается вызовом метода Lock(), который возвращает новую блокировку.

Метод acquire(blocking) нового объекта блокировки используется для принудительного синхронного выполнения потоков. Опциональный параметр blocking управляет тем, ждет ли поток получения блокировки.

Метод 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)

Модуль Queue позволяет создать новый объект очереди, который может содержать определенное количество элементов. Методы управления очередью:

Пример

#!/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

Python

  1. Нарезка резьбы формованием против накатки резьбы: понимание ключевых различий
  2. Освоение типов данных в Python: практическое руководство
  3. Мастерство операторов Python: Полное руководство
  4. Оператор pass в Python: практическое руководство
  5. Аргументы функций в Python: позиционные, именованные и параметры по умолчанию
  6. Словари в Python: создание, манипуляции и продвинутые техники
  7. Объектно-ориентированное программирование в Python: классы, наследование, инкапсуляция и полиморфизм
  8. Сетевое программирование в Python: сокеты и продвинутые протоколы
  9. Расширение Python на C: создание быстрых нативных модулей
  10. Освоение цикла резьбонарезания Fanuc G76: Полное руководство для наладчиков ЧПУ