Вопрос

Допустим, я хочу прочитать строку из сокета, используя стандартный socket модуль:

def read_line(s):
    ret = ''

    while True:
        c = s.recv(1)

        if c == '\n' or c == '':
            break
        else:
            ret += c

    return ret

Что именно происходит в s.recv(1)?Будет ли он выполнять системный вызов каждый раз?Думаю, мне все равно стоит добавить немного буферизации:

Для наилучшего соответствия аппаратным и сетевым реалиям значение размер буфера должна быть относительно небольшая степень 2, например, 4096.

http://docs.python.org/library/socket.html#socket .разъем.recv

Но написать эффективную и потокобезопасную буферизацию, кажется, непросто.Что, если я использую file.readline()?

# does this work well, is it efficiently buffered?
s.makefile().readline()
Это было полезно?

Решение

Тот Самый recv() вызов обрабатывается непосредственно путем вызова библиотечной функции языка Си.

Это заблокирует ожидание получения данных из сокета.На самом деле это просто позволит recv() блокировка системного вызова.

file.readline() это эффективная буферизованная реализация.Он не является потокобезопасным, поскольку предполагает, что файл читает только он.(Например, путем буферизации предстоящих входных данных.)

Если вы используете файловый объект, каждый раз read() вызывается с положительным аргументом, базовый код будет recv() только объем запрашиваемых данных, если только они уже не буферизованы.

Он был бы буферизован, если бы:

  • вы вызвали функцию readline(), которая считывает полный буфер

  • конец строки был перед концом буфера

Таким образом, оставляя данные в буфере.В противном случае буфер, как правило, не переполняется.

Цель этого вопроса не ясна.если вам нужно проверить, доступны ли данные перед чтением, вы можете select() или переведите сокет в неблокирующий режим с помощью s.setblocking(False).Затем чтение вернет пустоту, а не блокирующую, если ожидающих данных нет.

Вы читаете один файл или сокет с несколькими потоками?Я бы поставил одного работника на чтение сокета и отправку полученных элементов в очередь для обработки другими потоками.

Предложите консультацию Исходный код модуля сокета Python и Источник C, который выполняет системные вызовы.

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

Если вы беспокоитесь о производительности и полностью контролируете розетку (вы не передаете его в библиотеку, например), затем попробуйте реализовать ваша собственная буферизация в Python - Python string.find и string.split и тому подобное быть удивительно быстрым.

def linesplit(socket):
    buffer = socket.recv(4096)
    buffering = True
    while buffering:
        if "\n" in buffer:
            (line, buffer) = buffer.split("\n", 1)
            yield line + "\n"
        else:
            more = socket.recv(4096)
            if not more:
                buffering = False
            else:
                buffer += more
    if buffer:
        yield buffer

Если вы ожидаете, что полезная нагрузка будет состоять из строк которые не слишком большие, которые должны бежать довольно быстро, и избегайте прыгать через слишком много слоев функций звонит без необходимости. Мне было бы интересно узнать как это можно сравнить с file.readline () или с помощью socket.recv (1).

def buffered_readlines(pull_next_chunk, buf_size=4096):
  """
  pull_next_chunk is callable that should accept one positional argument max_len,
  i.e. socket.recv or file().read and returns string of up to max_len long or
  empty one when nothing left to read.

  >>> for line in buffered_readlines(socket.recv, 16384):
  ...   print line
    ...
  >>> # the following code won't read whole file into memory
  ... # before splitting it into lines like .readlines method
  ... # of file does. Also it won't block until FIFO-file is closed
  ...
  >>> for line in buffered_readlines(open('huge_file').read):
  ...   # process it on per-line basis
        ...
  >>>
  """
  chunks = []
  while True:
    chunk = pull_next_chunk(buf_size)
    if not chunk:
      if chunks:
        yield ''.join(chunks)
      break
    if not '\n' in chunk:
      chunks.append(chunk)
      continue
    chunk = chunk.split('\n')
    if chunks:
      yield ''.join(chunks + [chunk[0]])
    else:
      yield chunk[0]
    for line in chunk[1:-1]:
      yield line
    if chunk[-1]:
      chunks = [chunk[-1]]
    else:
      chunks = []
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top