Pull to refresh
20
0
Денис @ftc

Программист

Send message

Я разобрался https://habr.com/ru/post/724682/. Дело действительно в Nagle.
TL;DR: NODELAY надо выставлять с обеих сторон. Сочетание write+write+read - проблемное, ненадотак.

APCu я бы тут отнёс к читерству, потому что добраться из не-php процесса до этого самого APCu будет проблемно.

Да, почитал, там внутрях SysV https://github.com/krakjoe/apcu/blob/master/apc_shm.c

И совершенно логичным образом всех заруливает "ручная" работа с памятью через FFI :-)

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

Тестовый пример на то и тестовый, переписать на 8 версию не так сложно (тем более, что сборку расширения под 8.2 я уже починил).

Если не нужно очищать ресурсы, то по идее надо сохранять объект, который ими управляет, в области видимости (ну, вернуть его там или сохранить куда).
А про finally согласен.
В этом плане становится сложно, например, в C#, ибо даже вылетевший из области видимости объект, вообще говоря не удаляется. И что делать, кроме как явно очищать всякие файлы и сокеты (или возиться с IDisposable, но по сути, тоже, явно) - непонятно.

Справедливости ради, не golang единым - примерно в любом языке, где есть деструкторы или обработка исключений (в лице блока finally), goto в кейсе "не забыть очистить ресурсы", особо-то и не нужен.
А вот break/continue с метками был бы полезен, много где.

Подозреваю, что "под капотом" что shmget/shmat, что shm_open/mmap обращаются к одним и тем же механизмам ядра, API просто разное.
Потому думаю, что существенной разницы в производительности не будет. Но для POSIX разделяемой памяти, опять же, надо своё расширение к PHP писать (как и с семафорами).

Имеете в виду, положить php-объект сразу в расшаренную память? Звучит интересно. Чисто технически, можно написать расширение, которое будет создавать объекты (ну, хотя бы строки), которые сразу доступны из обоих процессов.

Про shm_get_var не в курсе, но вполне возможно она делает именно то, что вы описываете.

Да, когда я писал расширения к Perl, там у меня как раз была сборка Perl-объекта на стороне C++ и возврат его в Perl целиком. Единственное неудобство - так как в Perl сборщик мусора основан на ссылках (refcount), надо очень аккуратно за ними следить, я в какой-то момент долго разбирался, почему память утекает.

Пожалуй, это стоит отдельно поизучать. Займусь как-нибудь на досуге, самому интересно, странный очень эффект.

Тоже об этом думал. Добавил вариант с этой опцией, но результаты не поменялись.

Testing 1000 requests, reconnect after 1000 size 128
Testing IP socket:
Total: 28.123 seconds, 35.558 RPS
Testing IP socket with TCP_NODELAY:
Total: 28.151 seconds, 35.523 RPS
Testing Unix socket:
Total: 10.174 seconds, 98.294 RPS
Testing shared memory channel:
Total: 0.039 seconds, 25698.345 RPS
Testing 1000 requests, reconnect after 1 size 128
Testing IP socket:
Total: 10.303 seconds, 97.057 RPS
Testing IP socket with TCP_NODELAY:
Total: 10.306 seconds, 97.029 RPS
Testing Unix socket:
Total: 10.203 seconds, 98.009 RPS
Testing shared memory channel:
Total: 10.396 seconds, 96.191 RPS

Да, но тогда строго говоря надо самостоятельно следить за потерями пакетов и что-то предпринимать по этому поводу (мы ж не можем просто "забить" на непришедший ответ).
Понятно, что в рамках одной машины пакеты скорее всего теряться не будут, но строго говоря никто этого не гарантирует :-)

В тестовом сервере обработка заключается в банальном проходе по строке и подсчёту числа символов с разными кодами. Потому вряд ли в скорости обработки дело.
Возможно сказывается время на первичную установку коннекта. Для интереса прогнал тест с 1000000 запросов, результаты вот:

Testing 1000000 requests, reconnect after 1000000 size 128 
Testing shared memory channel: 
Total: 20.809 seconds, 48055.132 RPS
Testing 1000000 requests, reconnect after 1000000 size 2048
Testing shared memory channel:
Total: 217.817 seconds, 4591.005 RPS

Ну потому что "большие данные" это не про размер данных, а про способы работы с ними.

Статический метод - дак по имени класса же FB.fb(x). А изнутри объекта (из не-статического метода) - просто по имени.


Дело не в том, что близко к сердцу или нет, а в том, что "что мы доказываем". Если доказываем "на языке X можно быстро написать что-то годное за счёт удобных языковых средств" - в таком случае непонятно, зачем мерять производительность (ну т.е. это прям совсем не основная характеристика при таком сравнении), а надо скорее сравнивать лёгкость написания / понимания / расширения.

А если доказываем "на языке X можно написать, чтобы быстро работало" - то тогда надо сравнивать более-менее идиоматичные способы написания "чтобы быстро работало". Ну либо бескомпромиссно оптимизировать, но эт уже нужны специалисты в каждом конкретном ЯП и лучше тогда в виде соревнования какого-то.

В общем, я не очень понял, что хотели сравнить, отсюда и вопросы.

Что же касается размера влинкованного рантайма (или размера интерпретатора) - дак он сильно зависит и от компилятора в том числе. Хотя конечно даёт некоторую информацию на тему "сколько надо потратить места, чтобы на сферическом компьютере в вакууме запустить эту программу". С другой стороны - когда он статически слинкован, нам на каждую программу своя копия рантайма нужна, а если мы про php там или джаву, то он более-менее один на всех. Впрочем, эт уже отдельная история.

Ну мы ж тут вроде скорость дефолтного рантайма замеряем :-) Так что шарп стоило включить.

Очень странное сравнение, как по мне. Если уж сравнивать производительность - то не решения "в лоб" или решения "максимально задействующего синтаксический сахар", а "решения, в котором сколько-нибудь заморочились с производительностью".

В плюсах - если уж хотим использовать iostream, то стоит выключить синхронизацию с stdio, чтобы буферизация работала std::ios::sync_with_stdio(false); . Там же, в плюсах, похоже компилятор решил весь C++-ный рантайм статически слинковать. Оно конечно удобно, но вообще говоря не то чтобы принято (ну т.е. под винды стоит компилировать MSVC и использовать его системные dll-ки, под пингвинов - системный же libc).

В джаве я не очень понял, зачем делать объект FB внутри main, а потом дёргать у него статический метод, в котором снова создаётся объект того же FB.

Вот к go, python и php придраться особо негде, по крайней мере на первый взгляд. А в остальных я не силён.

Про Retry-After давно не слышал. Хотя в университете про HTTP и его заголовки очень даже рассказывали (и даже просили написать HTTP-сервер).

А вот про Authorization не со всем соглашусь - бывает, что нужно всю информацию, требуемую для запроса, положить в URL. Например - токены доступа по ссылке (когда нужно что-то расшарить людям, которым известна ссылка, по типу документов в Google Drive). Потому в каждом случае надо отдельно разбираться.

А ещё, раз уж про авторизацию заговорили, можно вспомнить Basic HTTP Auth, для которого в частности имя пользователя и пароль можно задавать прямо в URL: <scheme>://<user>:<password>@<host>/<path>. И это даже вполне себе работает.

Увы, фоток датчика не осталось. Впрочем, там ничего сверхъестественного - два джека 3.5 и от них кабель, на конце обмотанный изолентой (внутри резисторы и термистор.

Information

Rating
Does not participate
Registered
Activity

Specialization

Mobile Application Developer, Game Developer
Lead
C#
C++
Unity3d
PHP