LINUX.ORG.RU

Асинхронность как чтение буфера - TCP и HTTP сервер

 , , ,


1

3

Для своего проекта мне нужно реализовать передачу данных по протоколу TCP. Моих знаний и опыта хватило для примитивного сервера на Python:

  • Программа работает, выполняет одну задача за другой
  • В какой-то момент послылает запрос и приостанавливает свою работу, пока не получит ответ
  • Получает ответ и продолжает свою работу Но это очень неэффективно, особенно когда нужно передавать очень тяжёлые файлы по несколько гигабайт:
  • Программа условно разделяет файл на небольшие чанки.
  • Посылает запрос с чанком файла, а следующий чанк отправит только после получения ответа о текущем

Максимальная скорость передачи, которую мне удалось достичь - 4 мегабайта в секунду в локальной сети. Было бы гораздо эффективнее просто закидать сервер тысячами пакетов, и собирать ответы от сервера в буфер, в который периодически можно поглядывать, чтобы потом докинуть неудачные пакеты.

И в этом заключается странность ситуации. Мне не хватает текущих знаний - в колледже об этом вообще ничего не говорили, но я представляю работу с сетью себе примерно так:

  • Программа создаёт сокет
  • Настраивает сокет
  • Биндит сокет на порт
  • Когда приходит запрос или ответ на запрос - операционная система записывает данные в некий «буфер входящих пакетов»
  • Программа читает часть «буфера входящих пакетов»

И если это действительно так - то я хочу добиться асинхронности за счёт «««редкого считывания»»» буфера. То есть программа будет делать другие дела помимо ожидания ответа, например - работа с интерфейсом (а то программа, которая пошлёт пакет и будет рисовать интерфейс одновременно - тупо зависнет, а параллельность не везде возможна), или послать ещё запрос, а потом ещё и ещё, хотя ответ на первый запрос ещё не пришёл.

Да, в Python существуют библиотеки для асинхронной работы, но асинхронность в высоких языках я воспринимаю как мега-ужасный костыль - она быстро превращает проект в мега-сложную и сверх-запутанную структуру с огромным количеством абстракций и систем защиты от «гонок». Любой проект превращается из простого «сделать это а потом то» в «держать абстрактный класс с содержанием других классов, наследующих от других классов другие классы», и для моего не самого гениального мозга это воспринимается как мусор, в котором абстрактность на абстрактности, и абстрактность абстрактностью погоняет.

Мне кажется, что асинхронность на более низком уровне - это очень простая вещь, например просто «««редкое считывание»»» буфера. Никаких потоков, «гонок», семафоров и IPC. Просто буфер, который иногда можно читать. И вообще, я воспринимаю асинхронность на низком уровне как просто очень грамотно спроектированную программу, которая эффективно тратит время - на работу, а не на пустое ожидание.

Почему не хочу использовать многопоточность?

  1. Мой проект должен работать на любом тостере, на любом самоваре, а значит - многопоточности может и не оказаться.
  2. Я считаю многопоточность огромным усложнением проекта - в нём сразу возникнет куча проблем с «гонками», семафорами и безопасностью.
  3. Многопоточность ускорит работу сети в 2-24 раза, а грамотная асинхронность - в сотни тысяч раз, если не в миллионы или миллиарды.

Почему не async из Python? Потому что это костыль е_аный, а не асинхронность.

Я хочу использовать HTTP, и пока не знаю, как мне подружить его с такой «буферной асинхронностью», если она будет реализована самостоятельно. Поэтому было бы неплохо достичь «адекватной с моей точки зрения» асинхронности в Python. Может, написать библиотеку, которая даёт доступ и функции для работы с «буфером входящих пакетов», может даже в виде простого Python списка. Нет, я не буду писать свой проект полностью на Си - боюсь, что каждый самостоятельно написанный парсер не будет учитывать миллионы давно открытых уязвимостей, и в итоге мой проект будет решетом. Тут я не против абстракций, когда дело касается безопасности.

Плохой новостью для меня окажется, если просто поглядывать в буфер раз в 1/4 секунды - не выйдет, по причинам типа:

  • Accept переводит процесс в состояние «заблокировано», пока не будет установлено соединение
  • Listen переводит процесс в состояние «заблокировано», пока не придёт новый пакет

И типа из-за этого программа не сможет заняться своими делами, такими как отрисовка интерфейса и отправка других, следующих пакетов. Было бы печально, если бы такое не получилось.

В общем и целом - помогите разобраться в самоучке.

Покидайте полезных статей с примерами, пожалуйста, я сейчас нахожу только воду и статьи, сгенерированные нейросетями, аля «чтобы добиться асинхронного TCP соединения на Python…» и дальше какой-то абстрактный код, который потом превращается в Java, а затем в рецепт салата Цезарь из резиновых покрышек.

Ну или просто помогите разобраться, как эта работа с сетью работает на низком уровне. Я верно мыслю о «грамотной асинхронности» через «редкое считывание» некого «буфера входящих соединений», или же я неправильно предположила, и такое невозможно, и всё это лишь глупая мечта наивной сишницы?

Хочу добиться своего на Си или Python.

Спасибо заранее ^~^



Последнее исправление: Linux-Music-Girl (всего исправлений: 2)
Ответ на: комментарий от hateyoufeel

А «event poll» - это проверка флага «в буфере событий что-то есть» и проход по этому самому буферу событий? В SDL2 обработку событий можно реализовать через простенький буфер, и это делает проект очень лёгким и простым для понимания и работы.

Linux-Music-Girl
() автор топика
Ответ на: комментарий от Linux-Music-Girl

А «event poll» - это проверка флага «в буфере событий что-то есть» и проход по этому самому буферу событий?

Event loop – это цикл в твоей программе, где она обрабатывает входящие события (отсюда название). Наличие данных в сокете – одно таких из событий. Питоновская asyncio делает это за тебя (https://docs.python.org/3/library/asyncio-eventloop.html), но никто не мешает написать это руками и хуже.

hateyoufeel ★★★★★
()

Про какие пакеты речь, если ты работаешь по tcp? Ты решил реализовать tcp внутри tcp?

должен работать на любом тостере

на Python

Вопросов больше не имею

cobold ★★★★★
()

бери libuv.org и будет как в node.js :-) или другой event-loop, их много много, на вкус и цвет

про сделать «асинхронность как в питоне», огорчу - её там нет вообще :-) в питоне нет своего event-loop, только внешние.

MKuznetsov ★★★★★
()

4 Мб/с - не такая уж маленькая скорость для сетевого интерфейса. За счёт чего Вы хотите увеличить скорость?
Вот приложение отправило чанк и ждёт - так ведь оно ждёт, пока освободится ПОЛНОСТЬЮ ЗАНЯТЫЙ передачей сетевой интерфейс. Потом, правда, ещё ждёт некоего ответа, но это видимо, миллисекунды на каждый чанк? Не выглядит большой проблемой.

PeleWin ★
()
Ответ на: комментарий от PeleWin

Основная трата времени - ожидание ответа от сервера аля «я всё получил и обработал». Но, видимо, проблема ещё и с тем как реализована передача, тут я уже начинаю понимать, что мною была допущена глупость - передача происходит через requests, который, видимо, для каждого запроса и ответа создаёт и удаляет соединение, вместо того, чтобы создать соединение, и работать с ним до конца выполнения задачи, обрывая соединение только в нужный момент времени. Может, если реализовать немного по-другому - то получится значительно ускорить процесс. Но всё ещё не решается проблема с серверной части - сервер должен периодически делать какую-то работу, а не строго ждать запросов. Хотя, глядя на все эти сложности, мне уже кажется, что проще спроектировать API так, что никакая параллельная работа не понадобится. Но всё-таки хочется асинхронность попробовать, сейчас повторно пытаюсь изучить asyncio из Python, может получится через aiohttp всё сделать, не прям уж сильно усложняя проект. Вообще сейчас думаю, что зря вопрос написала - ведь проблема в том что я не изучила матчасть. Если скажу для чего я вообще это всё делаю - меня вообще загрызут за неправильность тут и там…

Linux-Music-Girl
() автор топика
Ответ на: комментарий от Linux-Music-Girl

в удалёных короткий буклет 188 страниц целиком об async[io] питона

если в сырцы не очень

прокури rAft ;) и в целом от чего «ща» мода на конкурентоность(бегуны спутники с латыни) стала массовой (закон мура ой) хотя

qulinxao3 ★☆
()
Последнее исправление: qulinxao3 (всего исправлений: 1)
Ответ на: комментарий от Reset

Пост не читай, сразу отвечай!

Да, в Python существуют библиотеки для асинхронной работы, но асинхронность в высоких языках я воспринимаю как мега-ужасный костыль - она быстро превращает проект в мега-сложную и сверх-запутанную структуру с огромным количеством абстракций и систем защиты от «гонок». Любой проект превращается из простого «сделать это а потом то» в «держать абстрактный класс с содержанием других классов, наследующих от других классов другие классы», и для моего не самого гениального мозга это воспринимается как мусор, в котором абстрактность на абстрактности, и абстрактность абстрактностью погоняет.

Хочется ОПу потрахаться. Ты против что ли?

hateyoufeel ★★★★★
()

Как по мне, то проще всего запустить отдельный поток и в нем читать данные. Потом уведомить главный поток о том что весь файл получен. Модуля threading в Python и его документации должно хватить.

urxvt ★★★★★
()

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

sendfile.

anonymous
()
Ответ на: комментарий от hateyoufeel

В asyncio абстракций минимум. Просто маркируй функции как async и где надо зови await на чтении/записи. Да и откуда гонки если все работает в один поток?

Reset ★★★★★
()
  • Markdown
Пустая строка (два раза Enter) начинает новый абзац. Знак '>' в начале абзаца выделяет абзац курсивом цитирования.
Внимание: прочитайте описание разметки Markdown.
Используйте Ctrl-Enter для размещения комментария