Python's time.sleep - никогда не просыпаться - PullRequest
4 голосов
/ 26 февраля 2010

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

[ СТОП ПРЕСС: Я был прав. Решение было найдено. Смотрите ответы. ]

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

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

К фрагменту кода относится:

 logging.info("Sleep starting")
 time.sleep(5)
 logging.info("Waking up")

Теперь странная часть. Я вижу сообщение журнала «Запуск из режима сна», но не сообщение «Пробуждение». Программа блокируется и не отвечает на прерывание клавиатуры (CTRL + C). Загрузка процессора очень низкая.

Я вижу ту же проблему в Windows и Ubuntu (Python 2.6.2).

Я размышлял, происходит ли исключение и скрывается ли он, поэтому я добавляю «print 1/0» между первой и второй строкой - я вижу, что возникает ошибка деления на ноль. Я перевожу его после сна и никогда не вижу сообщения.

Я подумал: «Хорошо, может быть, другой поток пытается одновременно что-то записать что-то очень большое, и он все еще буферизируется. Что он делает?»

Что ж, к этому времени тест вернулся к юнит-тесту, где он приостанавливает ожидание запуска потока перед проверкой состояния системы.

 logging.info("Test sleep starting")
 time.sleep(0.25)
 logging.info("Test waking up")

Ух ты, это выглядит знакомо. Точно так же замерзает! Первое сообщение журнала появляется, второе нет.

Недавно я провел значительную переписку устройства, поэтому не могу утверждать, что «я ничего не трогал», но я не вижу ничего плохого в своих изменениях.

Подозрительные зоны:

  • Я в том числе использую Threading.Lock (потому что я не знаю, как рассуждать о безопасности GIL, поэтому я придерживаюсь того, что знаю. Я не вижу ничего «тупикового» в своем коде.

  • Я новичок в юнит-тесте Python. Есть ли что-то, что он делает с перенаправлением регистрации или подобным, который может симулировать эти симптомы?

  • Нет, я не подставил нестандартный модуль времени!

Что помешает пробуждению нити? Что еще я пропустил?

Ответы [ 2 ]

5 голосов
/ 27 февраля 2010

Вздох.

Рабочий поток № 1 спит, а потом просыпается. Затем он будет регистрировать сообщение о пробуждении и блокируется. Только один поток может быть одновременно.

Тема UnitTest спит, а потом просыпается. Затем он будет регистрировать сообщение о пробуждении и блокируется. Только один поток может быть одновременно.

Worker-Thread-Not-ранее-ранее-In-The-The-Question # 2 тихо заканчивал обработку элемента PREVIOUS в очереди, пока первый рабочий поток спал. Дошло до записи в журнале. Одним из параметров был объект, и str () был вызван неявно. В функции str () этого объекта была ошибка; он зашёл в тупик, когда получил доступ к некоторым своим членам данных. Произошла взаимоблокировка во время обработки функцией регистрации, таким образом сохраняя блокировку потока регистрации и создавая впечатление, что другие потоки никогда не просыпаются.

Тест деления на ноль не имел значения, потому что в результате была сделана попытка записи.

0 голосов
/ 01 мая 2012

В Linux попробуйте изменить планировщик ввода-вывода на Полностью честную очередь (CFQ).

echo cfq > /sys/block/sda/queue/scheduler
...