Подтвердить что ты не робот

Я не могу понять опрос /select в python

Я выполняю эксперимент с асинхронной сетью с потоками в python, используя UDP.

Я хотел бы понять опрос и выбрать модуль python, я никогда не использовал их в C/С++.

Для чего нужны? Я вроде немного понимаю, но блокирует ли он, наблюдая за ресурсом? Какова цель опроса?

4b9b3361

Ответ 1

Если вы выполняете read или recv, вы ожидаете только одного соединения. Если у вас несколько подключений, вам придется создавать несколько процессов или потоков, отходы системного ресурса.

С помощью select или poll или epoll вы можете отслеживать несколько подключений только одним потоком и получать уведомление, когда у кого-либо из них есть доступные данные, а затем вы вызываете read или recv на соответствующее соединение.

Он может блокироваться бесконечно, блокировать в течение определенного времени или вообще не блокировать в зависимости от аргументов.

Ответ 2

Хорошо, один вопрос.

Что это за?

Вот простой скелет сервера сокетов:

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)

В этом случае сервер не может принимать никаких дополнительных подключений.

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

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 готов к чтению/записи/исключению.

он (выбирает) блок во время просмотра ресурса?

Да, или нет, зависит от параметра, который вы передали ему.

Как выберите man-страницу, он получит параметр 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 */
};

Есть три случая:

  • timeout.tv_sec == 0 и timeout.tv_usec = 0

    Без блокировки, немедленно вернуться

  • timeout == NULL

    навсегда, пока не будет готов дескриптор файла.

  • Время ожидания нормальное

    ждать определенное время, если файл дескриптора файла недоступен, время ожидания и возврат.

Какова цель опроса?

Положите это на простые слова: опрос освобождает CPU для других работ, ожидая IO.

Это основано на простых фактах, что

  • Процессор намного быстрее, чем IO
  • ожидание ввода-вывода - пустая трата времени, потому что в течение самого времени CPU будет простаивать

Надеюсь, что это поможет.

Ответ 3

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() - они не будут вызваны для пустого списка....

Если сокет готов к чтению, тогда, если у него будут данные, он также не будет блокироваться.