Как реализовать threaded socket.recv() в python?

#python #multithreading #sockets #locking

#python #многопоточность #сокеты #блокировка

Вопрос:

У меня есть несколько устройств, с которых мне нужно получать обновления статуса. Объект socket — это все, что у меня есть, а socket.recv() — это все, что мне нужно для получения статуса. При установке в однопоточное приложение проблем не возникает:

 class Device:
    def receive(self):
        log.debug("receive waiting: %r", self.device_id)
        try:
            packet = self.socket.recv(255)
        except Exception as e:
            self.report_socket_error(e)
            self.reconnect()
        log.debug("received response: %r", self.device_id)
d = Device()
d.connect()
while True:
    d.receive()
  

Однако тот же код, завернутый в многопоточность.Класс Thread вызывает взаимоблокировки и странное поведение. Обертывание его блокировками ничего не изменило. Я проследил проблему вплоть до socket.recv() call…So как реализовать несколько потоков, где каждый поток владеет одним сокетом (1 поток владеет исключительно 1 сокетом), которые могут ожидать данных одновременно?

Заранее спасибо

Комментарии:

1. Почему вы устанавливаете блокировку? Вы используете какой-либо ресурс? отправка / recv в соответствии с POSIX являются атомарными операциями. Возможно, вы недостаточно хорошо использовали потоковую обработку. Можете ли вы поделиться кодом, в котором вы реализовали потоки?

Ответ №1:

Я знаю, что это не отвечает на ваш вопрос о том, как решить вашу проблему взаимоблокировки, однако, похоже, что использование потоков в вашем случае является накладным:

Вы можете просто использовать один поток, в котором вы используете select() , чтобы выяснить, в каком сокете есть доступные данные, а затем обработать сообщенные данные. Если обработка не занимает много времени или ваш протокол не сложнее select , все должно быть в порядке и избегать всех проблем с потоками.

Взгляните на http://docs.python.org/howto/sockets.html#non-blocking-sockets для получения дополнительной информации.

Ответ №2:

Из скольких разных сокетов вам нужно читать?

  • Если ответ «только один», то используйте только один поток. Добавление другого никак вам не поможет, а только усложнит вашу жизнь, как вы выяснили.
  • Если ответ «несколько», то один из способов организовать это — действительно иметь поток на сокет. recv это блокирующая операция, которая делает поток привлекательным вариантом для организации кода. Каждый поток владеет отдельным сокетом и читает из него на досуге. У вас не должно возникнуть проблем и взаимоблокировок с этим.

    Блокировки не нужны, пока ресурсы не являются общими. Даже если вы совместно используете ресурсы (ведение журнала, некоторое хранилище данных и т.д.), Не используйте просто простые блокировки — в Python для этого есть утилиты более высокого уровня, такие как Queue module.