Почему signal.pause () предотвращает поломку сокетов?

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

Если я выполню это так, я получу BrokenPipeError, который прерывает программу, несмотря на цикл while True и блок except.

#!/usr/bin/env python3
import signal
import traceback
from multiprocessing.dummy import Pool
from process import Process

def main():
    while True:
        try:
            # a Process has a couple threads
            process = Process()
            listener_pool = Pool(processes=1)
            sender_pool = Pool(processes=1)

            # blocking socket client that runs forever
            listener_pool.apply_async(process.listener_thread.run, ())

            # blocking socket server that runs forever
            sender_pool.apply_async(process.sender_thread.run, ())

            return 0

        except BrokenPipeError:
            traceback.print_exc()

            # closing connections
            process.emitter_thread.socket.close()
            process.listener_thread.socket.close()

if __name__ == '__main__':
    main()

Однако, когда я добавил signal.pause() прямо перед возвратом, не только код работал так, как задумано, но и BrokenPipeError не вызывается в любое время.

#!/usr/bin/env python3
import signal
import traceback
from multiprocessing.dummy import Pool
from process import Process

def main():
    while True:
        try:
            # a Process has a couple threads
            process = Process()
            listener_pool = Pool(processes=1)
            sender_pool = Pool(processes=1)

            # blocking socket client that runs forever
            listener_pool.apply_async(process.listener_thread.run, ())

            # blocking socket server that runs forever
            sender_pool.apply_async(process.sender_thread.run, ())
            signal.pause()
            return 0

        except BrokenPipeError:
            traceback.print_exc()

            # closing connections
            process.emitter_thread.socket.close()
            process.listener_thread.socket.close()


if __name__ == '__main__':
    main()

Согласно документы, сигналы могут обрабатываться только основным потоком, но оба сокета обрабатываются вторичными потоками. Что делает signal.pause() для предотвращения поломки сокетов, когда они даже не вызываются в одном контексте?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
209
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

apply_async, как следует из названия, возвращается немедленно. Поэтому в первой версии вашей программы основной поток завершается сразу после запуска дочерних потоков (фиктивные процессы - это просто потоки, использующие многопроцессорный API).

Следовательно, основной поток вышел из блока try задолго до возникновения исключения.

Во втором случае signal.pause() заставляет основной поток ждать в блоке try, где он перехватит исключение.

Обратите внимание, что это хрупкое решение, поскольку получение сигнала любой приведет к возобновлению работы signal.pause() и выходу из основного потока.

Кстати, это ваше дизайнерское решение, но если вы работаете с python3.5 +, переход в асинхронный режим намного удобнее, чем потоки Python (будь то потоки или многопроцессорность api).

spectras 13.06.2018 00:17

Спасибо за ответ. Но тогда разве traceback.print_exc() не предупредит меня, что сокет сломан, вместо того, чтобы тихо выйти из строя? Я убрал код, чтобы его было легче читать, но оба потока по крайней мере записывали критические исключения в файл журнала. Я даже переместил signal.pause();return 0 ниже блока except, и у меня все еще нет BrokenPipeError. Означает ли это, что никакие сокеты не выходят из строя?

Ramon Melo 13.06.2018 00:22

Это, вероятно, означает, что они не терпят неудачу. Конечно, вы можете попробовать сделать одну ошибку намеренно, вы должны увидеть исключение.

spectras 13.06.2018 00:24

Просто попробовал. Они действительно не терпят неудач. Я поигрался с заменой signal.pause() with time.sleep () `и считаю, что основной поток после выхода закрыл все соединения (возможно, как часть сборки мусора). Спасибо за помощь, теперь я понимаю, что здесь нужно исправить.

Ramon Melo 13.06.2018 00:48

Другие вопросы по теме