TGViewer
Channel Public Channel
Чайник из Юты

Чайник из Юты

@irrationalthings

Не смешно
Subscribers
122
Photos
216
Videos
3
Links
144

Showing posts older than #75 · Back to latest

Older Posts 20 shown
Post #73 204
Я вспомнил пароль от канала

Автор перешёл на голанг, теперь буду писать заметки конкретно об этом языке.

Итак, с чего бы хотелось интересного начать (точнее, что у меня сейчас на уме) - loop unrolling. По сути, базовая оптимизация, когда вместо цикла мы просто много раз повторяем инструкции. Это пошло ещё с древних времён, почему циклы работают медленней развёрнутых - я без понятия. В голанге, к слову, тоже присутствует такая проблема, так как каждая итерация занимает ровно 2 наносекунды, что порой может быть критичным

Чтобы упростить дальнейшее понимание данной штуки - приведу пример на Го:

data := "Hello, world!"

for _, char := range data {
fmt.Println(char)
}

Данный код выведет построчно Hello, world!. При развёртывании же цикла, мы будем иметь нечто вроде:

fmt.Println("H")
fmt.Println("e")
fmt.Println("l")
fmt.Println("l")
fmt.Println("o")
...

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

data := "Hello, world!"

i := 0
dataLen := len(data)

for {
fmt.Println(data[i])
fmt.Printlnb(data[i+1])
fmt.Println(data[i+2])
fmt.Println(data[i+3])

i += 4

if dataLen-i < 4 {
break
}
}

for i < dataLen {
fmt.Println(data[i])
i++
}

Что мы здесь видим? Мы совершаем в ~4 раза меньше итераций, поскольку вместо 4 итераций, мы делаем 4 операции в одной. Можно выставить как 4, так и 6, и 8, и вообще 20 как шаг. Единственное - рекомендую выставлять число, равное степени двойки.

Что по поводу выигрыша - у меня он составил около 35% при шаге в 8 и строке длиною 5,000 элементов. Что, я считаю, очень даже весомо, особенно в ситуациях, когда входных данных достаточно много (экспериментальным путём я пока не успел выяснить, при насколько малых объемах выигрыш становится не столь существенным). Да, это усугубляет читаемость. Да, из-за неё у нас появляется копипаста кода. Да, в некоторых случаях это может превратиться в кучу одинакового кода, если результат каждой операции нужно как-то обрабатывать (к примеру - обрабатывать возврат ошибки функции). И тем не менее, быстрый код - зачастую противоположность красоте, посему не рекомендую городить такие штуки в коде, в котором не настолько важна производительность.

Подводя итоги, хочу сказать, что штука действительно ситуативная. Использовать, или нет - дело сугубо каждое. Посему - спешу откланяться и поблагодарить того, кто прочитал всю эту вероятно бесполезную простыню больного шизофренией маньяка оптимизаций
  • 👍 1
  • 👎 1
Post #72 182

Forwarded from Айван

Столкнулся с тем что __pycache__ директории в проекте доставляют неудобства: когда переключаюсь между git ветками, остаются папки которых нет в ветке, из-за того что в них есть незакоммиченные __pycache__.
Решил как-нибудь избавиться от них, нашёл вопрос на stackoverflow.
В комментариях предложили добавить в ~/.bashrc
export PYTHONPYCACHEPREFIX=/tmp
(/tmp папка со временными файлами, будет очищена спустя какое-то время, или при перезапуске компьютера)
Stack Overflow Changing the directory where .pyc files are created Is there a way to change the directory where .pyc file are created by the Python interpreter? I saw two PEPs about that subject (0304 and 3147), but none seems to be implemented in the default
  • 👍 1
  • 👎 1
Post #70 204
Новая цель - 400к РПС на статичном файле.
#roadtothe400kRPS #родтзе400кРПС
  • 👎 1
Post #69 226
Чайник из Юты А, новая цель. Выжать 250к RPS на том же статичном файле. #roadtothe250kRPS #родтзе250кРПС
Цель - перевыполнена. Оказалось, что самой необходимой оптимизацией - была смена парсера. http-parser оказался слишком медленным, и сменив его на httptools - производительность выросла на 100к РПС (!!!). Чутка пооптимизировав, я добился ещё 50к рпс. В итоге, имеем +150к рпс. Ну и, соответственно, меньшую задержку
  • 👎 1
Post #68 165
Осталось придумать, как мне сделать нормально кэширование. Поскольку на данный момент, у каждого из процессов свой кэш со своими in-memory закэшированными файлами. Получается, до оптимизации в прошлом посте, расход памяти на кэширование был примерно 2n, где n - количество логических ядер процессора. После оптимизации, расход стал просто n, что всё ещё так-то много. В идеале, должен быть расход 1. Что-то вроде доп. процесса, который занят только кэшированием внутри себя, и отдающим кэшированные версии запросов/файлов процессам. Но учитывая, как работает multiprocessing.Queue (на IPC+Pickle, что опять таки не очень-то и шустро), это неплохо так ухудшит производительность. А этого я допустить не могу. Штош, поставлю себе в TODO, но куда-нибудь далеко
  • 👎 1
Post #67 121
Давно заметил печальный факт, что в погоне за производительностью, я совсем потерял счёт памяти. Всё кэширование у меня работает по принципу "отдельно сам файл, отдельно кэшированный ответ с этим файлом". По сути, я хранил в каждом процессе по 2 дубликата одного и того же файла, просто во втором дубликате были ещё и хттп хедеры. Наконец, руки дошли до поработать над вебсервером, по итогу починиль - теперь пре-рендерятся только хедеры, а само тело файла уже при каждом запросе прихерячивается к заголовкам
  • 👎 1
Post #66 122
Как conn.getpeername() 10-15к рпс сожрал

Был отличный день для привнесения новых фич. Я и подумал: пора добавить в класс Request новый аттрибут - IP-адрес пользователя. Какого же было мое удивление, когда из-за этого, производительность упала в среднем на уже вышеупомянутые 10-15к рпс. Видимо, просто conn.getpeername() мутит под капотом что-то тёмное, что и дало мне понять: лучше так не делать
  • 👎 1
Post #65 112
Чайник из Юты Итак - цель частично выполнена. Частично - потому что это тестируется лишь эксперементальная, PoC-фича. Я просто реализовал кеширование ответов с файлами (почему нет - они ведь всегда одни и те же). И реализовал я это прямо в объекте rush.core.entities.Request.…
Что самое интересное, к слову, на то, чтобы повысить производительность на 17.5%, мне понадобилось всего 8 строчек кода
  • 👎 1
Post #63 112
А, новая цель. Выжать 250к RPS на том же статичном файле. #roadtothe250kRPS #родтзе250кРПС
  • 👎 1
Post #62 97
Чайник из Юты Цель выполнена: выжать 50к РПС. На данный момент, с 4 форками (5 процессами), вебсервер выдает такие результаты: 100к рпс для статичного кешированного файла, 120к рпс для статичного перманентного редиректа (который происходит внутри вебсервера). Следующая…
Итак - цель частично выполнена. Частично - потому что это тестируется лишь эксперементальная, PoC-фича. Я просто реализовал кеширование ответов с файлами (почему нет - они ведь всегда одни и те же). И реализовал я это прямо в объекте rush.core.entities.Request. Это, конечно, круто, но для этих целей я собираюсь (в отдельной ветке, конечно же) имплементировать сессионный движок - на каждого нового пользователя будет создаваться условно свой инстанс объекта Session, с кукисами, локальным кешированием и шлюхами
  • 👎 1
Post #60 74
Итак, я решил вести версионирование проекта. Буду делать это по старой-доброй схеме - майорный номер, минорный, и патч. Майорный будет отображать итерацию проекта, минорный - крупные изменения/привносения новых фич и возможностей в интерфейсе. Патчи же будут означать номер выпуска с багфиксами. На каждый багфикс/малейшее изменение в коде я, конечно, не буду инкрементировать патч, но это будет некого рода накопительные выпуски. Накапливается пачка багфиксов - выпускаю в релиз
  • 👎 1
Post #59 72
А если серьезно, то этому репозиторию уже года 3. И вот на самом деле, мне крайне обидно, ведь и на PyPI он тоже называется rush. Неужели мне придется публиковать репозиторий под именем rush-webserver?..
  • 👎 1
Post #58 69
Это, кстати, первый мат за всё время существования канала. Ну, что поделать. По такому поводу - можно
  • 👎 1
Post #57 83
Ахуеть. У меня, оказывается, имя проекта спиздили
  • 👎 1
Post #56 74
Установить можно, просто скачав файл куда угодно, и ввести команду pip3 install path/to/package/rush-2.0.0-py3-none-any.whl


Также, в скором времени намерен залить сеё произведение исскуства на PyPI, чтобы прям по красоте
  • 👎 1
Post #55 70
rush-2.0.0-py3-none-any.whl21.3 KB
Ну штош, столько времени спустя - могу себе позволить перекроить файловую иерархию вебсервера так, чтобы получился в итоге питоний пакет
  • 👎 1
Post #54 75
А ещё, гит почему-то перманентно игнорирует мою папочку logs. А её даже в гитигноре нет! Вручную git add logs/ ничего не дает. Магия, не иначе!

А мне ведь пришлось костылить пикрелейтед
  • 👎 1
Post #53 71
Оказывается, WSL не поддерживает флаг SO_REUSEPORT для сокетов. Держу в курсе

Пришлось для этого даже специально проверку делать, а не запускается ли вебсерв случаем под всл, и случаем не установлено ли количество серверных процессов на не-ноль
  • 👎 1
Post #51 67
Какая же производительность у сервера на 1 процессе? А вот.
  • 👎 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →