Уведомления

Группа в Telegram: @pythonsu

#1 Июль 19, 2010 01:25:09

nerijus
От:
Зарегистрирован: 2010-06-03
Сообщения: 93
Репутация: +  1  -
Профиль   Отправить e-mail  

Сигнал прерывания с клавиатуры

Alex2ndr
Сделал на threading.Event - вроде таких граблей нет.
Вот так с самого начала и надо было делать. Для общения с потоками нужно использовать события и Queue. Напрямую устанавливать флаги и проверять с разных потоков плохой тон, даже если язык гарантирует атомарность этих операций.



Отредактировано (Июль 19, 2010 01:26:20)

Офлайн

#2 Июль 19, 2010 16:52:41

Alex2ndr
От:
Зарегистрирован: 2009-12-26
Сообщения: 204
Репутация: +  0  -
Профиль   Отправить e-mail  

Сигнал прерывания с клавиатуры

nerijus
Вот так с самого начала и надо было делать.
Делал. Без переопределения join это все равно не работало. А старался использовать вариант с флагами т к “Simple is better than complex” - Если бы подощло простое решение, то зачем делать сложно?



Офлайн

#3 Июль 20, 2010 03:44:11

nerijus
От:
Зарегистрирован: 2010-06-03
Сообщения: 93
Репутация: +  1  -
Профиль   Отправить e-mail  

Сигнал прерывания с клавиатуры

Alex2ndr
Делал. Без переопределения join это все равно не работало.
С join все в порядке. Дело просто в том что join как и например socket.accept, блокирует поток и при этом не получает KeyboardInterrupt. А это исключение получает только главный поток. Так что нужно запустить цикл со sleep или join с таймаоутом (что вы практически и пытались неявно сделать переписывая сам join). Главное тут не попасть в блокировку на долго.

Alex2ndr
т к “Simple is better than complex” - Если бы подощло простое решение, то зачем делать сложно?
Не спорю. Но иногда сделать все очень просто не выходит. Хотя этот случай и не из таких. Я тут невижу никаких сложностей.



Офлайн

#4 Июль 20, 2010 12:51:26

ZZZ
От: Москва
Зарегистрирован: 2008-04-03
Сообщения: 2161
Репутация: +  26  -
Профиль   Адрес электронной почты  

Сигнал прерывания с клавиатуры

Согласен тобой, nerijus. threading.Event тут явно правильнее обычного флага.
Если бы нужно было бы сделать АПИ не для внутреннего использования, я бы использовал property, так как это явно красивее. Но тут это уже лишнее.



Офлайн

#5 Июль 20, 2010 13:52:52

Alex2ndr
От:
Зарегистрирован: 2009-12-26
Сообщения: 204
Репутация: +  0  -
Профиль   Отправить e-mail  

Сигнал прерывания с клавиатуры

В дополнение к этой теме еще 2 статейки(если можно так выразится):
http://habrahabr.ru/blogs/python/84629/
http://community.livejournal.com/ru_python/275027.html
После изучения этого материала и ОСОЗНАНИЯ того факта, что когда мы в Main Thread сделали join, то управление к нему не возвращается никогда (ну или очень долго - дольше чем я ждал), мне стало понятно высказывание:

nerijus
С join все в порядке. Дело просто в том что join как и например socket.accept, блокирует поток и при этом не получает KeyboardInterrupt. А это исключение получает только главный поток. Так что нужно запустить цикл со sleep или join с таймаоутом (что вы практически и пытались неявно сделать переписывая сам join). Главное тут не попасть в блокировку на долго.
Т е решение было еще проще. Вместо того, чтобы делать join просто делаем бесконечный цикл, в котором проверяем флаг/событие и тд. Пойду пробовать…



Офлайн

#6 Июль 20, 2010 15:17:54

nerijus
От:
Зарегистрирован: 2010-06-03
Сообщения: 93
Репутация: +  1  -
Профиль   Отправить e-mail  

Сигнал прерывания с клавиатуры

Ненужно даже флаг в цикле проверять. Вот набросил маленький пример:

from threading import Thread
from time import sleep

class Worker(Thread):
def __init__(self):
Thread.__init__(self)
self.terminated = False

def run(self):
while not self.terminated:
sleep(1)

def terminate(self):
self.terminated = True
self.join()


if __name__ == '__main__':
worker = Worker()
worker.start()
try:
while True:
sleep(1)
except KeyboardInterrupt:
print "Ctrl-C"
worker.terminate()
print "Done"
Проверил на win32 и на BSD работает. Если твой поток может и сам завершится, то в место sleep(1), нужно поставить worker.join(1)



Офлайн

#7 Июль 20, 2010 21:59:21

Alex2ndr
От:
Зарегистрирован: 2009-12-26
Сообщения: 204
Репутация: +  0  -
Профиль   Отправить e-mail  

Сигнал прерывания с клавиатуры

Тогда такой вопрос: а если подойти архитектурно(как в соседней теме :) ) то насколько грамотен тот или иной подход? После изучения всего материала пришел к выводу, что результат в принципе получается одинаковым - т е выполнение перехватывается всеми потоками, в том числе и main thread. Разве что переопределять чужие функции, без должной причины, не хорошо…



Офлайн

#8 Июль 21, 2010 03:09:26

nerijus
От:
Зарегистрирован: 2010-06-03
Сообщения: 93
Репутация: +  1  -
Профиль   Отправить e-mail  

Сигнал прерывания с клавиатуры

Alex2ndr
т е выполнение перехватывается всеми потоками
Когда речь идет о потоках, важно не где часть кода лежит, о который поток его выполняет. Только не уверен правильно ли я вопрос понял :)

Alex2ndr
Разве что переопределять чужие функции, без должной причины, не хорошо…
Тут уж нужно смотреть сделаны ли эти методи как бы для расширения. Даже не знаю как тут луче объяснить… ну например переопределение Thread.run - ок, а Thread.join - плохо.



Офлайн

#9 Июль 21, 2010 09:43:27

ZZZ
От: Москва
Зарегистрирован: 2008-04-03
Сообщения: 2161
Репутация: +  26  -
Профиль   Адрес электронной почты  

Сигнал прерывания с клавиатуры

nerijus, в твоём подходе есть одно странное недоразумение… Все нити завершаются последовательно, а не параллельно. В общем-то иногда это будет хорошей фишкой, но нам уж лучше, чтобы оно быстрее завершалось.
Архитектурно такой приём мне не нравится. Не люблю:

        while True:
sleep(1)



Офлайн

#10 Июль 21, 2010 10:28:05

nerijus
От:
Зарегистрирован: 2010-06-03
Сообщения: 93
Репутация: +  1  -
Профиль   Отправить e-mail  

Сигнал прерывания с клавиатуры

ZZZ
в твоём подходе есть одно странное недоразумение… Все нити завершаются последовательно, а не параллельно.
А где у меня в примере ты видишь еще хотя бы один поток кроме main и worker? Для простоты я не делал никакого листа, пула и т.д. и не морочил этим себе голову.

ZZZ
Архитектурно такой приём мне не нравится. Не люблю:
А есть ли альтернатива когда поток ждет, ничего не делает, но при этом может получить о обработать KeyboardInterrupt? Если есть выкладывайте, сам буду рад увидеть :) Если нет, тогда предложите более элегантное решение.

ЗЫ: такой код вообще очень редко может использоваться. Много ли консольных програм которых нужно останавливать клавиатурой…



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version