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 ★★★★★
()