Перевод потока в спящий режим до наступления события X - PullRequest
6 голосов
/ 10 мая 2010

Я пишу много файлов в многопоточном приложении и создаю один обработчик для каждого файла. У меня есть класс HandlerFactory, который управляет распределением этих обработчиков. То, что я хотел бы сделать, это то, что

поток A запрашивает и получает дескриптор файла foo.txt из класса HandlerFactory

поток B запрашивает обработчик файла foo.txt

класс обработчика распознает, что этот дескриптор файла был извлечен

класс обработчика переводит поток A в спящий режим

поток B закрывает дескриптор файла, используя метод-обертку из HandlerFactory

HandlerFactory уведомляет спящие темы

поток B просыпается и успешно получает дескриптор файла foo.txt

Это то, что я имею до сих пор,

def get_handler(self, file_path, type):
    self.lock.acquire()
    if file_path not in self.handlers:
        self.handlers[file_path] = open(file_path, type)
    elif not self.handlers[file_path].closed:
        time.sleep(1)
    self.lock.release()
    return self.handlers[file_path][type]

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

Ответы [ 3 ]

6 голосов
/ 10 мая 2010

То, что вы ищете, называется условной переменной.

Переменные состояния

Здесь - это ссылка на библиотеку Python 2.
Для Python 3 его можно найти здесь

2 голосов
/ 10 мая 2010

Похоже, вы хотите threading.Semaphore , связанный с каждым обработчиком (другие объекты синхронизации, такие как События и Условия, также возможны, но Семафор кажется самым простым для ваших нужд). (В частности, используйте BoundedSemaphore : для вашего случая использования это немедленно вызовет исключение для ошибок программирования, которые ошибочно выпускают семафон чаще, чем они его получают - и это как раз причина того, что ограниченная версия семафонов; -).

Инициализируйте каждый семафор значением 1 при его создании (это означает, что обработчик доступен). Каждый использующий поток вызывает acquire на семафоре, чтобы получить обработчик (который может его блокировать), и release на нем, когда это сделано с обработчиком (который разблокирует ровно один из ожидающих потоков). Это проще, чем жизненный цикл получения / ожидания / уведомления / выпуска Условия, и также более перспективно на будущее, поскольку в документации по Условию сказано:

Текущая реализация просыпается ровно одна нить, если есть ожидание. Тем не менее, это не безопасно полагаться на это поведение. Будущее, оптимизированная реализация может иногда просыпаюсь больше чем один нить.

в то время как с Семафором вы играете безопасно (семантика, на которую безопасна, чтобы на нее можно было положиться : если семафор инициализирован в N, всегда есть между 0 и N-1 [[ включены]] темы, которые успешно приобрели семафор и еще не выпустили его).

0 голосов
/ 10 мая 2010

Вы понимаете, что Python имеет гигантскую блокировку, так что большинство преимуществ многопоточности вы не получите, верно?

Если у главного потока нет причин делать что-то с результатами каждого работника, вы можете подумать о том, чтобы просто отключить другой процесс для каждого запроса. Вам не придется иметь дело с проблемами блокировки. Пусть дети сделают то, что им нужно, а затем умрут. Если им нужно связаться обратно, сделайте это по каналу, с XMLRPC или через базу данных sqlite (которая является поточно-ориентированной).

...