pal201
Май 7, 2010 20:43:34
Есть функция выхода:
def sys_exit():
print u'Работа программы завершена...'
sys.exit(1)
Так вот программа, после ее вызова не завершается. Выводит принт и все.
Приходится использовать:
os.kill(0,signal.SIGKILL)
В чем может быть дело?
система ubuntu…10, до этого была 9, то же самое.
Спасибо.
Андрей Светлов
Май 7, 2010 21:55:51
Возможно, у вас остался работающий non-daemon thread.
pal201
Май 8, 2010 14:42:40
Совершенно верно, потоки есть. Но у потоков нет метода их завершения, на сколько я понял. После запуска run поток будет вполняться неограниченно долго.
А если потоков еще не запущено, то sys.exit вообще ничего не делает. Странно это как-то
pal201
Май 8, 2010 21:49:09
Вроде как после завершения родительского процесса все потоки должны завершаться? что-то этого не наблюдается…. Хочется услышать мнение профессионалов на этот счет.
Андрей Светлов
Май 8, 2010 23:05:36
Давайте сначала о sys.exit.
Вызов этой функции просто выбрасывает исключение SystemExit.
Которое обычно не ловится пользовательским кодом, а выпадает наружу, где и обрабатывается как завершение процесса.
Теперь о потоках.
Они бывают daemon и не daemon.
Обычные - не демоны. Они должны закончиться перед завершением программы. Питон будет их ждать, если нужно.
threading.Thread API не имеет метода “прибить поток”, и это правильно. Принудительное завершение потока не может быть безопасным по определению.
По правильному это делается через установку флага/события или еще чего нибудь, на что поток должен ответить завершением. А после установки флажка - дождаться через .join()
Поток можно переключить через setDaemon(True) перед стартом. Запущенный поток сделать демоном нельзя.
Питон не ожидает завершения демонов при финише.
Несмотря на кажущуюся привлекательность сильно не рекомендую их использовать.
Первое: как правило, демоны - признак плохого дизайна. Незамутненный “код с душком” по Фаулеру.
Вторая причина прозаичней и веселее. Потоки-демоны живут еще чуть-чуть после завершения главного потока. Сколько - заранее не скажешь. Просто планировщик может успеть сделать несколько переключений на них. И окружение в это время наполовину разрушено. Т.е. может уже не быть каких-нибудь модулей или глобальных объектов. В результате поток уваливается на какой-нибудь весьма странной ошибке. Которая еще и не воспроизводится стабильно.
Резюме: за своими потоками нужно следить. Если создал поток - всегда дождись его .join() Если поток нужно прервать - выставляй сигнал и анализируй его внутри потока. Отступления от правил караются средой исполнения.
PooH
Май 9, 2010 10:59:11
Андрей, вы не думали книгу написать? Все время интересные места выбираете и излагаете ясно.
Андрей Светлов
Май 11, 2010 16:57:31
Книгу писать - это вам не на форуме языком молоть.
Всерьез - не думал.
Zubchick
Май 11, 2010 20:12:43
напишите методичку :)
У вас отличное знание внутренностей, тем кто с питоном уже на ты, будет приятно узнать о том как это работает, а то большиснтво книг дают такое среднеповерхностное знание об этом.
Андрей Светлов
Май 11, 2010 22:10:52
А вы читайте исходники перед сном. Чужие, разумеется - на чтении своих научиться невозможно.
У CPython, к слову, довольно простой и понятный код. В отличие от многих питонячьих библиотек.