SocketServer ThreadingMixВ целях server_thread

В примере асинхронного (поточного) SocketServer http://docs.python.org/2/library/socketserver.html запускается поток сервера (называемый server_thread), чтобы запускать новые потоки для каждого запроса. Из-за некоторых проблем с перехватом KeyboardInterrupts я начал искать аналогичный код и обнаружил, что нет никакой очевидной разницы, когда НЕ используется серверный поток, но ctrl-c действительно работает.

Хотя мой код работает, я бы очень хотел знать

1) Почему не работает простая попытка поймать KeyboardInterrupt при использовании server_thread?

2) Какая польза от server_thread из примера - в отличие от моего несколько более простого примера?

Из примера python SocketServer перехват прерывания клавиатуры в попытке не работает:

if __name__ == "__main__":
    server = ThreadedTCPServer(serverAddr, SomeCode)
<snip>
    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.start()

Мой более простой пример, ctrl-c работает.

if __name__ == "__main__":
    server = ThreadedTCPServer(serverAddr, SomeCode)
    try:
        server.serve_forever()
        print "ctrl-c to exit"
    except KeyboardInterrupt:
        print  "interrupt received, exiting"
        server.shutdown() 

person user135361    schedule 05.03.2014    source источник


Ответы (2)


1) Это общая проблема. Когда вы нажимаете CTRL+C, процессу отправляется сигнал. В процессе основной поток ловит сигнал и (если не обрабатывается должным образом) основной поток прерывается. Но этот сигнал не убивает другие потоки. И Python не остановится, пока есть потоки, не являющиеся демонами (потому что это было бы небезопасно). Если вы знаете, что делаете, вы можете добавить это:

server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()

и это должно работать сейчас (при условии, что вы сделаете что-то после server_thread.start(), например ожидание, иначе Python просто завершит работу, он не будет ждать потоков демона). Однако помните, что вы можете убить свой сервер во время какой-то важной операции. Чтобы избежать этого, вы должны реализовать какое-то изящное убийство:

import signal

if __name__ == "__main__":
    server = ThreadedTCPServer(serverAddr, SomeCode)

    # some code
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.start()
    # some code

    try:
        signal.pause()  # wait for a signal, perhaps in a loop?
    except:
        server.shutdown()  # graceful quit

2) Он просто запускает сервер в отдельном потоке. Возможно, идея заключалась в том, что вы можете тем временем делать другие операции? Если вы хотите только запустить сервер, в этом нет необходимости.

Также причина может быть в том, что я указал выше: изящный выход. Если вы просто прервете сервер, он умрет, возможно, во время какой-то важной операции.

person freakish    schedule 05.03.2014
comment
Вы можете прервать работу ThreadedTCPServer в файле serve_forever(). Ничего важного не делает. Важная задача может быть в потоках обработчика, которые вы, возможно, захотите подождать. - person User; 05.03.2014

В примере с серверным потоком вы запускаете новый поток, который обслуживает контент. Эта ветка запущена не как демон (deamon = False). Это означает, что программа не завершится, пока не будет выполнено server_forever(). Таким образом, основной поток ничего не делает, и программа ожидает закрытия потоков, не являющихся демонами.

  1. Единственная разница, которую я вижу, заключается в том, что этот новый поток не является основным потоком и, следовательно, не обрабатывает KeyboardInterrupt или другие вещи, которые делает основной поток.
  2. Это может быть полезно, если вы хотите интегрировать графический интерфейс с вашим сервером. Графический интерфейс может работать параллельно.
person User    schedule 05.03.2014
comment
«печать ctrl-c для выхода» все еще выполняется, поэтому я ожидаю, что попытка сработает. Если он просто останется в server_thread, то печать не должна работать, или я ошибаюсь? - person user135361; 05.03.2014
comment
Извините, какую печать вы имеете в виду? Не могли бы вы объяснить больше? - person User; 05.03.2014