> обязан регулярно слать подтверждения своей готовности принять данные (т.е. сведения о состоянии окна приёма).
Только при изменении этого окна.
> надо послать ей «нулевые данные»
«Нулевые данные» невозможно послать средствами уровня сокетов. И противоположная сторона не обязана это подтверждать (она воспринимает такое просто как дежурный ACK). Единственный гарантированный способ получить ответ другой стороны — послать реальные данные.
В случае TCP — только на уровне сессии можно это лечить надёжно и кроссплатформенно (keepaliveʼами протокола уже выше уровнем, нежели TCP, тогда можно вводить собственный таймаут).
> Однажды решил он обыграть хостера в «интеллектуальном поединке».
Универсальный вариант для решения таких проблем — выделение времени на нестандартные/дополнительные хотелки по принципу token bucket.
Например: в целом на всех клиентов — до полчаса в рабочий день от каждого саппортера, если нет авралов, но до 2 часов в день в пике.
На одного клиента — до 5 минут в день, в пике до часа, и если есть время из пункта в целом на всех клиентов. Потратил свой час (подсказывает кэп) — дальше по 5 минут в день, если будет тратить каждый день:) Пул запросов рассматривается как очередь (FIFO), запросы «протухают» за неделю, если не подтверждены повторным сообщением от клиента.
Преимущества такого подхода:
1. Чётко прописанный алгоритм (можно опубликовать и вывесить на сайте).
2. Гибкая буферизация перегрузки за счёт постепенного вползания в перегрузку, которая детектируется простейшими методами и поддаётся статистическому контролю.
3. Обучение юниоров и интернов на реальных ситуациях с реальными людьми :) (из можно и до половины времени направлять на решение этих доп. вопросов)
И тот «хитрож…мудрый» клиент в этом случае просто получил бы часть такого резервного времени, если есть. Если он один такой — ну, молодец, получил бонус и дал саппорту чуть больше опыта. Если бы было много — он бы столько ресурсов не получил.
Что не решается, очевидно — проблема плачей типа «ну и что, я самый больной клиент на свете, мне нужно варенье в первую очередь», нужна сила воли, чтобы удержаться от перекосов (ну или желание сделать таки выбор по своим критериям, а не по громкости плача). И начальство может говорить «это же значит, что сотрудники недозагружены», тогда надо тщательно объяснять, что разумная недозагрузка это как раз нормально, потому что даёт гибкость и перспективу.
> с другой — все эти «мелочи», когда они идут потоком, ну просто нереально отвлекают сисадмина.
Всё равно надо закладывать резерв времени на непредвиденное, и если нет явных внутренних проблем, то пусть это время пойдёт на клиента.
Кроме уже сказанного про теорию погрешности вычислений (которая уже очень хорошо развита) — IEEE754, в частности, добивался, чтобы была возможность гарантированно повторить одни и те же результаты — даже если они заведомо неточны — на любых соответствующих стандарту системах, и результаты должны совпадать. Любые подобные «незначительные ошибки в десятом знаке» нарушают гарантию воспроизводимости и ставят под сомнение все результаты расчётов.
Они постоянно появляются. Например, «замерзание» SkyLake, которое лечится новым микрокодом, или ошибки в TSX, которые не лечатся (соответственно, всё до SkyLake реально не умеет TSX). Да и вообще, новый микрокод всегда что-то лечит :)
Разница с описанной в статье ситуацией — что ведущие производители 1) поняли, что лучше сразу сказать об ошибке, чем долго и нудно заметать под ковёр и в итоге таки потерять в репутации, 2) научились продумывать методы программного лечения (даже если это выключение недоработанных режимов или активация более медленного аналога).
В мире существует много опыта составления действительно электронных анкет, причём толковых, а не таких ужасных. Например, вопрос вида «лучшая сортировка» может иметь из 5 ответов 2 заведомо некорректных и 3 относительно нормальных (например, heapsort может входить как вариант). В зависимости от ответа можно менять набор последующих вопросов, а сами вопросы можно варьировать по стилю, случайным образом переставлять порядок вопросов и ответов, чтобы нельзя было угадать не зная тематику… Здесь, точно так же, как у типичного колл-центра, масса возможностей как составить инструкцию такому голосовому роботу предельно тупо, и достаточно возможностей сделать это умно, сразу получив прикидку на опыт и специфику кандидата. Но это же надо постараться сделать… а тут явно была реализация «на отцепись».
Ну я бы в таком случае ответил, что наиболее эффективный метод — это использовать готовую инструкцию POPCNT, а если у вас процессор её не умеет — дешевле его заменить :) Формально и для enterprise подхода — это было бы ещё правильнее (но не для попугая на входе).
Почему promise API несимметричен относительно деления на первичные функции (в new) и вторичные (во then/catch)?
В первичных надо получать аргументами resolve и reject, и вызывать их явно (проверил на promise 7.1.1 для nodejs — простой return со значением игнорируется, как будто промис незавершён).
Во вторичных надо возвращать значение или генерировать исключение, параметров resolve, reject нет.
Я бы понял логику, или что
1) у всех функций-коллбэков возврат значения работает как resolve с этим значением, а генерация исключения — как reject,
или что
2) все функции-коллбэки имеют три входных параметра — input, resolve, reject,
а лучше — и то, и другое (можно вернуть значение в конце, а можно — вернуть исключение и выйти; а ещё лучше — предусмотреть специальный тип исключения для resolve).
Также нет возможности написать .resolve(значение), и аналогично для reject — тоже было бы значительно удобнее (и извне, как уже обсуждают, и изнутри). (Тогда можно было бы вторым параметром передавать сам объект промиса, для вызовов его методов.)
Или я не вижу каких-то хитростей, которые решают это, и которые можно найти только с заметным опытом их использования?
> Проблема не в пропускной способности, а в сетевых задержках.
Я рассматривал в контексте передачи сравнимого с от «100,000 обращениями к оперативной памяти» и до «1,000,000,000 тактов» объёма передачи, там задержки уровня одного пакета уже не столь существенны, а скорость значительно больше влияет на общую задержку. В контексте коротких передач — да, безусловно, суммарные задержки важнее, и пример «512 байт из iRAM по сети vs. HDD локально, которому надо ещё переместить головки на полный диапазон» — отличная иллюстрация.
> Но ведь 100.000 обращений к оперативной памяти делается операциями, которые сами по себе займут 100.000 * x тактов?
64 чтения из областей, не входящих в одну выровненную 64-байтную область (как строка кэша), займут ~64*250 тактов. 64 чтения подряд из одной такой области займут, по описанной таблице, 64*4 такта. Достаточно просить prefetch на одну такую строку в начале чтения предыдущей, чтобы последовательное чтение не задерживало процессор. В реальности ситуацию ещё больше улучшают микросхемы памяти с несколькими одновременно открытыми строками и многоканальные контроллеры памяти.
> Как часто можно встретить ситуацию, когда 100.000 раз обращений к оперативки выгоднее, чем одно обращение к диску, особенно учитывая существование SSD и PCI-SSD?
При хоть сколь-нибудь продуманном доступе к памяти — считаем, практически всегда.
> Тем более, что сетевой сокет в гигабитной локалке, может быть быстрее, чем обращение к диску.
Гигабитный — по сравнению с SATA даже 1-м — уже нет :) Вот 10GB, или Infiniband'овские скорости — да, уже стоит упоминать.
Именно эта статья — нет, но аналогичные — да. Cетевой транспорт некоторого специфического протокола (средняя длина сообщения около 200 байт); внутреннее представление сообщения — или разложение в таблицу пар имя=значение, или как две строки (std::string, заголовок и тело) с манипуляцией над строкой с массовыми перемещениями частей при вставлении или удалении тегов. Без проблем медленной RAM — работа с разложенным представлением была бы в разы быстрее, но с учётом медленной памяти и кэширования — работа с цельными строками в ~2 раза быстрее. Ещё процентов 30 получается за счёт предаллокации строк на предполагаемую длину, вместо того, чтобы позволять рантайму несколько раз делать realloc.
Только при изменении этого окна.
> надо послать ей «нулевые данные»
«Нулевые данные» невозможно послать средствами уровня сокетов. И противоположная сторона не обязана это подтверждать (она воспринимает такое просто как дежурный ACK). Единственный гарантированный способ получить ответ другой стороны — послать реальные данные.
В случае TCP — только на уровне сессии можно это лечить надёжно и кроссплатформенно (keepaliveʼами протокола уже выше уровнем, нежели TCP, тогда можно вводить собственный таймаут).
Универсальный вариант для решения таких проблем — выделение времени на нестандартные/дополнительные хотелки по принципу token bucket.
Например: в целом на всех клиентов — до полчаса в рабочий день от каждого саппортера, если нет авралов, но до 2 часов в день в пике.
На одного клиента — до 5 минут в день, в пике до часа, и если есть время из пункта в целом на всех клиентов. Потратил свой час (подсказывает кэп) — дальше по 5 минут в день, если будет тратить каждый день:) Пул запросов рассматривается как очередь (FIFO), запросы «протухают» за неделю, если не подтверждены повторным сообщением от клиента.
Преимущества такого подхода:
1. Чётко прописанный алгоритм (можно опубликовать и вывесить на сайте).
2. Гибкая буферизация перегрузки за счёт постепенного вползания в перегрузку, которая детектируется простейшими методами и поддаётся статистическому контролю.
3. Обучение юниоров и интернов на реальных ситуациях с реальными людьми :) (из можно и до половины времени направлять на решение этих доп. вопросов)
И тот «хитрож…мудрый» клиент в этом случае просто получил бы часть такого резервного времени, если есть. Если он один такой — ну, молодец, получил бонус и дал саппорту чуть больше опыта. Если бы было много — он бы столько ресурсов не получил.
Что не решается, очевидно — проблема плачей типа «ну и что, я самый больной клиент на свете, мне нужно варенье в первую очередь», нужна сила воли, чтобы удержаться от перекосов (ну или желание сделать таки выбор по своим критериям, а не по громкости плача). И начальство может говорить «это же значит, что сотрудники недозагружены», тогда надо тщательно объяснять, что разумная недозагрузка это как раз нормально, потому что даёт гибкость и перспективу.
> с другой — все эти «мелочи», когда они идут потоком, ну просто нереально отвлекают сисадмина.
Всё равно надо закладывать резерв времени на непредвиденное, и если нет явных внутренних проблем, то пусть это время пойдёт на клиента.
Разница с описанной в статье ситуацией — что ведущие производители 1) поняли, что лучше сразу сказать об ошибке, чем долго и нудно заметать под ковёр и в итоге таки потерять в репутации, 2) научились продумывать методы программного лечения (даже если это выключение недоработанных режимов или активация более медленного аналога).
В первичных надо получать аргументами resolve и reject, и вызывать их явно (проверил на promise 7.1.1 для nodejs — простой return со значением игнорируется, как будто промис незавершён).
Во вторичных надо возвращать значение или генерировать исключение, параметров resolve, reject нет.
Я бы понял логику, или что
1) у всех функций-коллбэков возврат значения работает как resolve с этим значением, а генерация исключения — как reject,
или что
2) все функции-коллбэки имеют три входных параметра — input, resolve, reject,
а лучше — и то, и другое (можно вернуть значение в конце, а можно — вернуть исключение и выйти; а ещё лучше — предусмотреть специальный тип исключения для resolve).
Также нет возможности написать .resolve(значение), и аналогично для reject — тоже было бы значительно удобнее (и извне, как уже обсуждают, и изнутри). (Тогда можно было бы вторым параметром передавать сам объект промиса, для вызовов его методов.)
Или я не вижу каких-то хитростей, которые решают это, и которые можно найти только с заметным опытом их использования?
Я рассматривал в контексте передачи сравнимого с от «100,000 обращениями к оперативной памяти» и до «1,000,000,000 тактов» объёма передачи, там задержки уровня одного пакета уже не столь существенны, а скорость значительно больше влияет на общую задержку. В контексте коротких передач — да, безусловно, суммарные задержки важнее, и пример «512 байт из iRAM по сети vs. HDD локально, которому надо ещё переместить головки на полный диапазон» — отличная иллюстрация.
64 чтения из областей, не входящих в одну выровненную 64-байтную область (как строка кэша), займут ~64*250 тактов. 64 чтения подряд из одной такой области займут, по описанной таблице, 64*4 такта. Достаточно просить prefetch на одну такую строку в начале чтения предыдущей, чтобы последовательное чтение не задерживало процессор. В реальности ситуацию ещё больше улучшают микросхемы памяти с несколькими одновременно открытыми строками и многоканальные контроллеры памяти.
> Как часто можно встретить ситуацию, когда 100.000 раз обращений к оперативки выгоднее, чем одно обращение к диску, особенно учитывая существование SSD и PCI-SSD?
При хоть сколь-нибудь продуманном доступе к памяти — считаем, практически всегда.
> Тем более, что сетевой сокет в гигабитной локалке, может быть быстрее, чем обращение к диску.
Гигабитный — по сравнению с SATA даже 1-м — уже нет :) Вот 10GB, или Infiniband'овские скорости — да, уже стоит упоминать.