Я не могу понять опрос / выбор в python
Я делаю какой-то резьбовой асинхронный сетевой эксперимент в python, используя UDP.
Я хотел бы понять опрос и модуль select python, я никогда не использовал их в C / C++.
Что это ? Я немного понимаю выбор, но блокирует ли он во время просмотра ресурса ? Какова цель опроса ?
3 ответов
если у вас read
или recv
, вы ждете только одного соединения. Если у вас несколько соединений, вам придется создать несколько процессов или потоков, пустая трата системных ресурсов.
С select
или poll
или epoll
, вы можете контролировать несколько соединений только с одним потоком и получать уведомления, когда любой из них имеет доступные данные, а затем вы вызываете read
или recv
на соответствующее подключение.
он может блокировать бесконечно, блок для данного время, или не блокировать вообще, в зависимости от аргументов.
ладно, один вопрос один раз.
что это?
вот простой скелет сервера сокетов:
s_sock = socket.socket()
s_sock.bind()
s_sock.listen()
while True:
c_sock, c_addr = s_sock.accept()
process_client_sock(c_sock, c_addr)
сервер будет выполнять цикл и принимать соединение от клиента, а затем вызывать его функцию процесса для связи с клиентским сокетом. Здесь есть проблема: process_client_sock
может занять много времени или даже содержит цикл(что часто бывает).
def process_client_sock(c_sock, c_addr):
while True:
receive_or_send_data(c_sock)
в этом случае сервер не может принять больше подключение.
простое решение будет использовать multi-process или multi-thread, просто создайте новый поток для обработки запроса, в то время как основной цикл продолжает прослушивать новые соединения.
s_sock = socket.socket()
s_sock.bind()
s_sock.listen()
while True:
c_sock, c_addr = s_sock.accept()
thread = Thread(target=process_client_sock, args=(c_sock, c_addr))
thread.start()
это работает, конечно, но недостаточно хорошо, учитывая производительность. Поскольку новый процесс / поток требует дополнительного процессора и памяти, не простоя для серверов могут получить тысячи подключений.
так select
и poll
системные вызовы пытаются решить эту проблему. Вы даете select
набор файловых дескрипторов и сообщите ему, чтобы уведомить вас, если какой-либо fd готов к чтению/записи/ или исключению.
блокирует ли он (select) во время просмотра ресурса?
да, или нет, зависит от параметра, который вы передали ее.
As выберите man page говорит, достанет struct timeval
параметр
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
есть три случая:
-
тайм-аут.tv_sec == 0 и тайм-аут.tv_usec = 0
нет блокировки, немедленно вернуться
-
timeout == NULL
блокировать навсегда, пока файловый дескриптор не будет готов.
-
тайм-аут-это нормально
подождите определенное время, если по-прежнему нет дескриптора файла, тайм-аут и возврат.
какова цель опроса ?
положите его в простые слова: опрос освобождает CPU для других работ, когда ждем ИО.
это основано на простых фактах, что
- CPU намного быстрее, чем IO
- ожидание ввода-вывода-пустая трата времени, потому что в большинстве случаев CPU будет простаивать
надеюсь, что это помогает.
select () принимает 3 списка сокетов для проверки трех условий (чтение, запись, ошибка), а затем возвращает (обычно более короткие, часто пустые) списки сокетов, которые фактически готовы к обработке для этих условий.
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind((Local_IP, Port1))
s1.listen(5)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.bind((Local_IP, Port2))
s2.listen(5)
sockets_that_might_be_ready_to_read = [s1,s2]
sockets_that_might_be_ready_to_write_to = [s1,s2]
sockets_that_might_have_errors = [s1,s2]
([ready_to_read], [ready_to_write], [has_errors]) =
select.select([sockets_that_might_be_ready_to_read],
[sockets_that_might_be_ready_to_write_to],
[sockets_that_might_have_errors], timeout)
for sock in ready_to_read:
c,a = sock.accept()
data = sock.recv(128)
...
for sock in ready_to_write:
#process writes
...
for sock in has_errors:
#process errors
поэтому, если сокет не имеет попыток подключения после ожидания тайм-аута секунд, то список ready_to_read будет пустым - в этот момент не имеет значения, будут ли блокировать accept() и recv () - они не будут вызываться для пустого списка....
Если сокет готов к чтению, то если будет иметь данные, поэтому он не будет блокировать тогда.