Найти - Пользователи
Полная версия: Сигнал прерывания с клавиатуры
Начало » Python для экспертов » Сигнал прерывания с клавиатуры
1 2 3
nerijus
Alex2ndr
Сделал на threading.Event - вроде таких граблей нет.
Вот так с самого начала и надо было делать. Для общения с потоками нужно использовать события и Queue. Напрямую устанавливать флаги и проверять с разных потоков плохой тон, даже если язык гарантирует атомарность этих операций.
Alex2ndr
nerijus
Вот так с самого начала и надо было делать.
Делал. Без переопределения join это все равно не работало. А старался использовать вариант с флагами т к “Simple is better than complex” - Если бы подощло простое решение, то зачем делать сложно?
nerijus
Alex2ndr
Делал. Без переопределения join это все равно не работало.
С join все в порядке. Дело просто в том что join как и например socket.accept, блокирует поток и при этом не получает KeyboardInterrupt. А это исключение получает только главный поток. Так что нужно запустить цикл со sleep или join с таймаоутом (что вы практически и пытались неявно сделать переписывая сам join). Главное тут не попасть в блокировку на долго.

Alex2ndr
т к “Simple is better than complex” - Если бы подощло простое решение, то зачем делать сложно?
Не спорю. Но иногда сделать все очень просто не выходит. Хотя этот случай и не из таких. Я тут невижу никаких сложностей.
ZZZ
Согласен тобой, nerijus. threading.Event тут явно правильнее обычного флага.
Если бы нужно было бы сделать АПИ не для внутреннего использования, я бы использовал property, так как это явно красивее. Но тут это уже лишнее.
Alex2ndr
В дополнение к этой теме еще 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 просто делаем бесконечный цикл, в котором проверяем флаг/событие и тд. Пойду пробовать…
nerijus
Ненужно даже флаг в цикле проверять. Вот набросил маленький пример:

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

Alex2ndr
Разве что переопределять чужие функции, без должной причины, не хорошо…
Тут уж нужно смотреть сделаны ли эти методи как бы для расширения. Даже не знаю как тут луче объяснить… ну например переопределение Thread.run - ок, а Thread.join - плохо.
ZZZ
nerijus, в твоём подходе есть одно странное недоразумение… Все нити завершаются последовательно, а не параллельно. В общем-то иногда это будет хорошей фишкой, но нам уж лучше, чтобы оно быстрее завершалось.
Архитектурно такой приём мне не нравится. Не люблю:
        while True:
sleep(1)
nerijus
ZZZ
в твоём подходе есть одно странное недоразумение… Все нити завершаются последовательно, а не параллельно.
А где у меня в примере ты видишь еще хотя бы один поток кроме main и worker? Для простоты я не делал никакого листа, пула и т.д. и не морочил этим себе голову.

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

ЗЫ: такой код вообще очень редко может использоваться. Много ли консольных програм которых нужно останавливать клавиатурой…
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB