Выполнение многопоточных скриптов

Печать Предыдущая страница Стартовая страница Следующая страница

Поток в Python является объектом с рабочей функцией, которая указывается при создании экземпляра класса Thread (import threading). Пример реализации задачи содержится в базовом скрипте mindist.py.

Списки обрабатываемых пар объектов разбиваются на части, число которых соответствует числу потоков. Создаются объекты потоков по числу потоков и затем они запускаются методом start().

 

import threading

...

       self.numThreads = 8

       step = int(self.totalData/self.numThreads)+1

       for i in range(0, self.numThreads):

           c_from = i*step

           c_to   = i*step+step

           th = threading.Thread(target=self.CalcThread, args=(i,c_from,c_to))

           self.threads.append(th)

 

       for i in range(0,self.numThreads):

           self.threads[i].start()

 

Рабочая функция потока может быть объявлена в исходном коде скрипта один раз на весь модуль - конфликта между потоками это не вызывает. Рабочая функция может так же являться частью пользовательского класса.

 

def CalcThread(self, index, c_from, c_to)

       Идентификатор созданного объекта потока необходимо сохранить (например, в списке) - в противном случае сработает сборщик мусора.

 

for i in range(0,self.numThreads):    

 

  self.threads.append(th)

 

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

 

for i in range(0,self.numThreads):

             self.threads[i].start()    

 

Для разрешения ситуации одновременного доступа потоков к одному и тому же ресурсу (файл, общая переменная) следует использовать объекты мьютексы.

 

self.mutex = threading.Lock()        

self.mutex.acquire()

self.processed += 1

self.mutex.release()

 

Время жизни потока зависит от сложности кода его рабочей функции. Чтобы работа скрипта не завершилась раньше выхода всех дочерних потоков, следует использовать функцию join() класса Thread, если главный поток не контролирует сам завершение дочерних потоков. В этом случае основной поток скрипта дождётся завершения работы потока, к которому он присоединён функцией join(). Ошибки, возникающие внутри дочерних потоков, могут привести к их неопределенному поведению. Поэтому рекомендуется оборачивать код рабочей функции потока в конструкцию try ... except ... finally.