Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

[ Россум, Дрейк, Откидач ] Язык программирования Python

.pdf
Скачиваний:
282
Добавлен:
25.04.2014
Размер:
1.5 Mб
Скачать

22.2. threading — средства высокого уровня организации потоков

321

Thread([keyword_list])

Этот класс используется для представления потока. Конструктор воспринимает несколько именованных аргументов (keyword_list). Действия, выполняемые при запуске потока, могут быть установлены с помощью аргумента с именем target — должен быть объектом, поддерживающим вызов. Этот объект вызывается из метода run() с позиционными и именованными аргументами, заданными соответственно аргументами с именами args и kwargs (по умолчанию используются пустые кортеж и словарь). Аргумент с именем name указывает имя потока; по умолчанию используется ’Thread-N’, где N — десятичное представление небольшого целого числа.

Интерфейсы объектов описаны в следующих разделах.

22.2.1 Объекты, реализующие блокировку

Функции Lock() и RLock() возвращают объекты, имеющие одинаковый набор методов:

acquire([waitflag])

При вызове без аргументов захватывает (блокирует) объект, дождавшись, если это необходимо, его освобождения другим потокам (возвращает None). Если задан аргумент waitflag (целое число), поведение функции зависит от его значения: 1 — функция ожидает освобождения объекта другим потокам (так же, как и с опущенным аргументом), 0 (и другие значения) — объект захватывается только, если это может быть сделано немедленно. При наличии аргумента функция возвращает 1, если захват объекта прошел успешно, в противном случае возвращает 0.

release()

Освобождает объект. Объект должен быть захвачен ранее. Если метод применяется к объекту, возвращаемому функцией RLock(), объект должен быть захвачен этим же потоком.

В то время как объекты, возвращаемые функцией Lock(), реализуют примитивную блокировку (объект может быть захвачен один раз), для объектов, возвращаемых функцией RLock(), метод acquire() может быть вызван многократно одним потоком — для того, чтобы объект мог быть захвачен другим потоком, необходимо ровно столько же раз вызвать метод release().

22.2.2 Условия

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

322

Глава 22. Средства организации многопоточных программ

Объект, представляющий условие, имеет методы acquire() и release(), которые вызывают соответствующие методы ассоциированного объекта, реализующего блокировку. Он также имеет методы wait(), notify() и notifyAll(), которые должны вызываться только после того, как будет вызван метод acquire(). При вызове метода wait() объект-условие освобождает ассоциированный объект и блокирует выполнение до тех пор, пока из другого потока не будет вызван метод notify() или notifyAll(). После пробуждения метод снова захватывает ассоциированный объект. Вы можете указать максимальное время ожидания.

Методы notify() и notifyAll() не освобождают ассоциированный объект, реализующий блокировку. Таким образом, поток или потоки, вызвавшие метод wait(), будут пробуждены только после того, как поток, вызвавший notify() или notifyAll() окончательно освободит ассоциированный объект.

Приведем простой пример с производством и потреблением объектов. Пусть функция make_an_item_available() производит объект, get_an_available_item()

его потребляет и an_item_is_available() возвращает истину, если есть в наличии произведенные (но еще не употребленные) объекты. Тогда следующие фрагменты кода могут быть использованы в потоках производителя и потребителя соответственно:

# рТПЙЪЧПДЙН ПДЙО ПВЯЕЛФ cv.acquire() make_an_item_available() cv.notify() cv.release()

# рПФТЕВМСЕН ПДЙО ПВЯЕЛФ cv.acquire()

while not an_item_is_available(): cv.wait()

get_an_available_item()

cv.release()

acquire([...])

release()

Вызывают одноименные методы ассоциированного объекта, реализующего блокировку.

wait([timeout])

Освобождает ассоциированный объект, реализующий блокировку, ожидает, пока другим потоком не будет вызван метод notify() или notifyAll(), и снова захватывает ассоциированный объект. Если задан и не равен None аргумент timeout (вещественное число), он указывает максимальное время ожидания в секундах. По умолчанию время ожидания не ограничено.

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

22.2. threading — средства высокого уровня организации потоков

323

notify()

Пробуждает один поток, ожидающий выполнения условия, если таковой имеется.

notifyAll()

Пробуждает все потоки, ожидающие выполнения условия.

22.2.3Семафоры

Объекты, возвращаемые функцией Semaphore() имеют такой же набор методов, как и объекты, реализующие блокировку (см. раздел 22.2.1). Семафор управляет внутренним счетчиком, который уменьшается при каждом вызове метода acquire() и увеличивается при каждом вызове метода release(). Начальное значение счетчика определяет аргумент, переданный конструктору Semaphore(). Значение счетчика не может стать меньше нуля: вызов метода acquire() при значении счетчика равным нулю блокирует выполнение до тех пор, пока значение не увеличится, то есть пока другой поток не вызовет метод release().

22.2.4События

Объекты, возвращаемые функцией Event() реализуют простейший механизм взаимодействия потоков: один поток подает сигнал о возникновении события и один или более потоков ожидают его. Объект-событие имеет внутренний флаг. Если этот флаг является истиной, событие считается наступившим. Изначально (при создании объекта) флаг является ложью.

isSet()

Возвращает 1, если событие наступило (внутренний флаг является истиной).

set()

Устанавливает наступление события (внутренний флаг становится истинным). Все потоки, ожидающие события, пробуждаются.

clear()

Отменяет наступление события (внутренний флаг становится ложным).

wait([timeout])

Ожидает наступления события, то есть, если внутренний флаг является ложью, блокирует выполнение потока до тех пор, пока другой поток не вызовет метод set(). Если задан и не равен None аргумент timeout (вещественное число), он указывает максимальное время ожидания в секундах. По умолчанию время ожидания не ограничено.

324

Глава 22. Средства организации многопоточных программ

22.2.5Объекты, представляющие потоки

Экземпляры класса Thread представляют действия, выполняемые в отдельном потоке. Существует два способа определить эти действия: передача объекта, поддерживающего вызов, в качестве аргумента с именем target или переопределение метода run() в производных классах. В производных классах не следует переопределять другие методы, за исключением, возможно, конструктора. Если Вы переопределяете конструктор, не забудьте вызвать конструктор дочернего класса (Thread.__init__()) до того, как Вы будете что-либо делать с потоком.

После создания объекта, представляющего поток, Вы можете запустить его с помощью метода start(). После запуска поток считается активным до тех пор, пока не закончится выполнение метода run().

Каждый поток, реализованный с помощью Thread или производного от него класса имеет имя. Имя может быть задано при инициализации или с помощью метода setName() и извлечено с помощью метода getName().

Поток может “присоединиться” к другому потоку, вызвав метод join() объекта, представляющего этот поток. При этом выполнение потока, вызвавшего метод join() приостанавливается до тех пор, пока не завершится выполнение потока, к объекту которого был применен метод.

Поток может быть помечен как фоновый (daemon). Выполнение всей программы будет завершено только после того, как активными останутся только фоновые потоки. Начальное значение наследуется от текущего потока. Этот флаг может быть изменен с помощью метода setDaemon() и извлечен с помощью метода getDaemon().

Существует также объект, соответствующий основному потоку. Основной поток не является фоновым. Возможно также создание объектов, соответствующих “посторонним” потокам, то есть потокам, созданным без помощи модуля threading. Такие объекты имеют ограниченную функциональность. Они всегда считаются активными, фоновыми и к ним нельзя присоединиться с помощью метода join().

start()

Запускает выполнение задачи (метод run() объекта) в отдельном потоке. Этот метод может быть вызван не более одного раза.

run()

Этот метод представляет задачу, которая должна быть выполнена в отдельном потоке. Вы можете переопределить этот метод в производном классе. Стандартный метод run() вызывает функцию, указанную при инициализации объекта (аргумент с именем target).

join([timeout])

Этот метод приостанавливает работу текущего потока (который вызвал метод) до окончания выполнения потока, к объекту которого метод применяется. Если задан и не равен None аргумент timeout (вещественное число), он указывает макси-

22.3. Queue — синхронизированные очереди

325

мальное время в секундах ожидания завершения работы потока. По умолчанию (и если аргумент timeout равен None) время ожидания не ограничено.

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

Кпотоку нельзя присоединиться до того, как он будет запущен.

getName()

Возвращает имя потока.

setName(name)

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

isAlive()

Возвращает 1, если поток активен. Поток считается активным с момента вызова метода start() и до завершения выполнения задачи (метода run()).

isDaemon()

Возвращает значение внутреннего флага, который является истиной, если поток выполняется в фоновом режиме.

setDaemon(daemonic)

Устанавливает значение внутреннего флага, определяющего, в каком режиме выполняется поток, равным daemonic: если флаг является истиной, поток будет выполняться в фоновом режиме. Этот метод должен вызываться до запуска потока. Начальное значение наследуется от потока, создавшего данный поток.

Работа всей программы может быть завершена только после завершения работы всех нефоновых потоков.

22.3 Queue — синхронизированные очереди

Модуль Queue определяет класс, реализующий очередь (FIFO), доступ к которой может осуществляться из нескольких потоков. Доступность этого модуля зависит от наличия модуля thread.

Queue(maxsize)

Создает и возвращает объект-очередь. Аргумент maxsize (целое число) определяет максимальное количество элементов, которое можно поместить в очередь. По умолчанию, а также если maxsize меньше или равен нулю, размер очереди не ограничен.

Empty

Исключения этого класса генерируются при попытке извлечь из пустой или заблокированной очереди элемент с помощью метода get_nowait() (или get() с аргументом block равным нулю).

326

Глава 22. Средства организации многопоточных программ

Full

Исключения этого класса генерируются при попытке добавить в полную или заблокированную очередь элемент с помощью метода put_nowait() (или put() с аргументом block равным нулю).

Экземпляры класса Queue имеют следующие методы:

qsize()

Возвращает количество элементов в очереди (в момент вызова метода).

empty()

Возвращает 1, если очередь (в момент вызова метода) пуста, иначе возвращает 0.

full()

Возвращает 1, если очередь (в момент вызова метода) содержит максимальное количество элементов, иначе возвращает 0.

put(item [, block])

Добавляет элемент в очередь. Если аргумент block опущен или является истиной, выполнение потока при необходимости приостанавливается до тех пор, пока в очереди не появится свободное место. Если аргумент block является ложью, элемент добавляется в очередь только, если это можно сделать немедленно, в противном случае генерируется исключение Full.

put_nowait(item)

Эквивалентно вызову put(item, 0).

get([block])

Извлекает (удаляет) элемент из очереди и возвращает его. Если аргумент block опущен или является истиной, выполнение потока при необходимости приостанавливается до тех пор, пока в очереди не появится элемент. Если аргумент block является ложью, элемент извлекается из очереди только, если это можно сделать немедленно, в противном случае генерируется исключение Empty.

get_nowait()

Эквивалентно вызову get(0).

Не следует полагаться на значения, возвращаемые методами qsize(), empty() и full(): к моменту их получения ситуация может уже измениться.

327

Глава 23

Работа с базами данных

Модули, описанные в этой главе, предоставляют доступ к простым базам данных, реализуя интерфейс, аналогичным словарям. Во всех случаях в качестве ключа и значения могут использоваться только обычные строки1. Если Вы хотите хранить объекты языка Python другого типа, воспользуйтесь модулем shelve.

anydbm Универсальный интерфейс к базам данных в стиле DBM. dumbdbm Медленная, но переносимая реализация интерфейса DBM. dbhash Интерфейс в стиле DBM к библиотеке баз данных BSD. dbm Интерфейс к библиотеке (n)dbm.

gdbm Интерфейс к библиотеке gdbm.

whichdb Определяет, какой модуль с интерфейсом DBM был использован для создания файла базы данных.

bsddb Интерфейс к библиотеке баз данных BSD.

23.1Интерфейс к базам данных в стиле DBM

Модуль anydbm предоставляет универсальный интерфейс в стиле DBM к различным вариантам баз данных: dbhash (требует наличие модуля bsddb), gdbm или dbm. Если ни один из этих модулей не доступен, будет использована медленная, но полностью переносимая реализация на языке Python в модуле dumbdbm.

Модуль dbhash доступен в операционных системах UNIX и Windows и предоставляет интерфейс в стиле DBM к библиотеке BSD db. Для работы этого модуля необходим модуль bsddb.

Модули dbm и gdbm доступны только в операционных системах UNIX.

Заметим, что форматы файлов, создаваемых различными модулями не совместимы друг с другом.

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

328

Глава 23. Работа с базами данных

23.1.1 Общая для всех модулей часть интерфейса

Все перечисленные выше модули определяют функцию-конструктор и исключение:

open(filename [, flag [, mode]])

Открывает файл с именем filename базы данных и возвращает соответствующий ему объект. Если файл уже существует, функция anydbm.open() использует для определения его типа модуль whichdb и для файла используется соответствующий модуль. При создании нового файла anydbm.open() использует первый модуль из перечисленных выше, который может быть импортирован.

Аргумент flag может иметь одно из следующих значений:

’r’

Открыть существующий файл только для чтения (используется по умолчанию).

’w’

Открыть существующий файл для чтения и записи.

’c’

Открыть файл для чтения и записи. Если файл не существует, он будет создан.

’n’

Создать новую пустую базу данных (старый файл перезаписывается) и открыть ее для чтения и записи.

Вфункции dbhash.open() на платформах, поддерживающих блокировку, к флагу может быть добавлен символ ‘l’, если блокировка должна быть использована.

Вфункции gdbm.open() к флагу может быть добавлен символ ‘f’ для открытия файла в “быстром” режиме: в этом случае измененные данные не будут автоматически записываться в файл при каждом внесении изменений (см. также описание

метода sync() в разделе 23.1.3).

Аргумент mode указывает биты разрешений, которые будут установлены для файла, принимая во внимание маску разрешений (umask). По умолчанию используется

0666.

error

Класс исключений, которые генерируются в случае возникновения различных ошибок, характерных для данного модуля. Заметим, что если в базе данных отсутствует запись с определенным ключом, генерируется исключение KeyError.

Имя dbhash.error является псевдонимом для класса bsddb.error.

В модуле anydbm эта переменная ссылается на кортеж классов исключений, которые могут быть сгенерированы непосредственно модулем anydbm (первый элемент) или одним из модулей, реализующим доступ к базе данных. Это не вносит каких-либо неудобств, так как кортежи с классами исключений, указанные после ключевого слова except, могут быть вложенными произвольным образом.

Объекты, возвращаемые функциями open() всех перечисленных модулей, поддерживают большинство операций, характерных для отображений: извлечение, установка и

23.1. Интерфейс к базам данных в стиле DBM

329

удаление значений по ключу, а также методы has_key() и keys(). Ключи и значения должны быть обычными строками. Кроме того, эти объекты имеют еще один метод:

close()

Закрывает файл с базой данных.

Объекты, возвращаемые функциями dbhash.open() и gdbm.open(), имеют дополнительные методы, описанные ниже.

23.1.2Дополнительные методы объектов, возвращаемых функцией dbhash.open()

first()

Возвращает кортеж с ключом и значением первой записи в базе данных. Если база данных не содержит ни одной записи, генерируется исключение KeyError. Используя методы first() и next() Вы можете обойти все записи в базе данных.

next()

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

k, v = db.first() try:

print k, v

k, v = db.next() except KeyError:

pass

sync()

Сбрасывает на диск все не записанные данные.

23.1.3Дополнительные методы объектов, возвращаемых функцией gdbm.open()

firstkey()

Возвращает ключ первой записи в базе данных. Вы можете перебрать все записи базы данных с помощью методов firstkey() и nextkey().

nextkey(key)

Возвращает ключ к записи, следующей за записью с ключом key. Следующий пример выводит ключи для всех записей, не создавая списка ключей в памяти:

k = db.firstkey() while k != None:

print k

k = db.nextkey(k)

330

Глава 23. Работа с базами данных

reorganize()

Реорганизует файл базы данных, удаляя из него неиспользуемые участки. Может быть полезен после удаления большого количества записей (reorganize() — единственный метод, который может привести к уменьшению размера файла).

sync()

Сбрасывает на диск все не записанные данные.

23.2 whichdb — определение формата файла базы данных

Этот модуль определяет единственную функцию, которая пытается определить, какой модуль должен быть использован для открытия базы данных: dbm, gdbm или dbhash.

whichdb(filename)

Возвращает None — если файл filename отсутствует или к нему нет доступа на чтение, пустую строку (’’) — если формат файла неизвестен. В остальных случаях возвращает строку с именем модуля (например, ’gdbm’), который должен быть использован для открытия файла.

23.3bsddb — интерфейс к библиотеке баз данных BSD

Модуль bsddb предоставляет интерфейс к библиотеке BSD db2. С помощью этого модуля Вы можете создавать и работать с файлами баз данных типа “Hash”, “BTree” и “Record”. Объекты, возвращаемые функциями модуля, ведут себя аналогично словарям.

Первые три аргумента всех функций одинаковы: filename — имя файла базы данных, flag — флаги, определяющие способ открытия файла, и mode — биты разрешений (по умолчанию используется 0666), которые будут установлены для файла, принимая во внимание маску разрешений (umask). Аргумент flag может иметь одно из следующих значений:

’r’

Открыть существующий файл только для чтения (используется по умолчанию).

’w’

Открыть существующий файл для чтения и записи.

’c’

Открыть файл для чтения и записи. Если файл не существует, он будет создан.

2Обычно используется библиотека версии 1.85. Начиная с Python 2.0, версия библиотеки может быть указана при сборке. Следует помнить, что версии 1.85 и 2.0 библиотеки db несовместимы.