У меня есть несколько устройств, из которых мне нужно получить обновления статуса. Объект сокета - это все, что у меня есть, и 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()
Однако тот же код, заключенный в threading.Thread класс вызывает взаимоблокировки и смешное поведение. Обертка с помощью замков ничего не изменила. Я проследил проблему до вызова socket.recv()... Итак, как реализовать несколько потоков, в которых каждый поток владеет одним сокетом (1 поток владеет исключительно 1 сокетом), которые могут ждать данные одновременно?
Заранее спасибо
Я знаю, что это не отвечает на ваш вопрос о том, как исправить вашу проблему взаимоблокировки, однако кажется, что ваше использование потоков - это накладные расходы в вашем случае:
Вы можете просто использовать один поток, в котором вы используете select()
, чтобы узнать, какой сокет имеет доступные данные, а затем обрабатывать сообщенные данные. Если обработка занимает много времени или ваш протокол более сложный select
должен быть в порядке и избежать всех проблем с потоками.
Посмотрите http://docs.python.org/howto/sockets.html#non-blocking-sockets для более подробной информации.
Сколько разных сокетов вам нужно читать?
Если ответ "несколько", то один способ организовать это - действительно иметь поток для каждого сокета. recv
- это операция блокировки, которая делает поток привлекательным для организации кода. Каждая ветка владеет отдельным гнездом и читает от него на досуге. У вас не должно быть проблем и тупиков.
Замки не нужны, если ресурсы не разделены. Даже если вы используете общие ресурсы (ведение журнала, некоторое хранилище данных и т.д.), Вы не просто используете простые блокировки - у Python есть утилиты более высокого уровня, такие как модуль Queue
.