• Основы работы с фьютексами

    • Перевод
    Фьютекс (futex — сокращение от «Fast userspace mutex») — это механизм, предложенный разработчиками Linux из IBM в 2002 году и вошедший в ядро в конце 2003 года. Основной идеей было предоставить более эффективный способ синхронизации пользовательских потоков с минимальным количеством обращений к ядру ОС.

    В этой статье мы сделаем обзор фьютексов, попытаемся понять принципы их работы, а также используем их в качестве кирпичиков для построения более высокоуровневых (и знакомых нам) объектов синхронизации.

    Важный момент: фьютексы — это достаточно низкоуровневый инструмент, напрямую его использовать стоит лишь при разработке фундаментальных библиотек, вроде стандартной библиотеки C/C++. Очень маловероятно, что вам понадобится использовать фьютексы в обычном прикладном приложении.
    Читать дальше →
  • Воображаемые проблемы — корень плохого ПО

    • Перевод
    Есть много обстоятельств, которые могут быть катализаторами создания плохого ПО: используемые инструменты, качество коммуникаций в команде, персональные качества разработчиков, методологии и т.д. И есть среди них одна вещь, которая является корнем почти всех остальных: воображаемые проблемы.

    Большинство сложного или забагованого программного обеспечения не планировалось быть сложным и, уж тем более, забагованым. Оно просто было создано для выполнения не тех задач, которые лежали в основе первоначального замысла.

    История о подкастах


    Давайте представим себе, что вы записываете популярный подкаст и в какой-то момент задумались о создании собственного сайта — ну, знаете, с информацией о вашем подкасте, записями прошлых выпусков, статьями, ну и возможно, кое-какой рекламой. В самом деле, ну сколько можно делиться прибылью с какими-то там посторонними издателями?

    И вот вы решаете нанять людей, которые сделают для вас этот сайт. Вы пишете для них абсолютно чёткие требования:

    • Быстрая загрузка сайта в Северной Америке
    • Поддержка загрузки прошлых выпусков подкастов и трансляции в реальном времени текущих
    • Трансляция не должна падать или замирать в течении первых 15 минут для 99.99% пользователей. Желательно вообще никогда, но хотя бы так.
    • Интеграция с Google Adwords (а в будущем, возможно, и с аналогами)
    • Интеграция с трансляциями Facebook, поскольку там вы проводите свои передачи. Если можно создать альтернативное решение, которое будет позволять стримить более удобно — ещё лучше.

    Вы даёте эти требования разработчикам и, возможно, немного общаетесь с ними. Проходит 2 месяца. Они показывают вам демо и вы покрываетесь красными пятнами. Становится понятно, что вы только что выбросили в пропасть 15 000 $. То, что вам показали, совершенно неприемлемо ни с какой стороны, просто куча мусора. Вы хотите назад свои деньги, но поезд уже ушел.
    Читать дальше →
  • epoll и Windows IO Completion Ports: практическая разница

      Введение


      В этой статье мы попробуем разобраться чем на практике отличается механизм epoll от портов завершения (Windows I/O Completion Port или IOCP). Это может быть интересно системным архитекторам, проектирующим высокопроизводительные сетевые сервисы или программистам, портирующим сетевой код с Windows на Linux или наоборот.

      Обе эти технологии весьма эффективны для обработки большого количества сетевых соединений.

      Они отличаются от других методов по следующим пунктам:

      • Нет ограничений (кроме общих ресурсов системы) на общее количество наблюдаемых дескрипторов и типов событий
      • Масштабирование работает достаточно хорошо — если вы уже мониторите N дескрипторов, то переход к мониторингу N + 1 займёт очень мало времени и ресурсов
      • Достаточно легко задействовать пул потоков для параллельной обработки происходящих событий
      • Нет никакого смысла использовать при единичных сетевых соединениях. Все преимущества начинают проявляться при 1000+ соединений

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

      (Upd: данная статья — перевод)

      Читать дальше →
    • select / poll / epoll: практическая разница

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

      В этой статье мы рассмотрим:

      • select()
      • poll()
      • epoll()
      • libevent
      Читать дальше →
    • Психология читабельности кода

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

      Каждый программист старается писать хороший код. Читабельность — один из главных признаков такого кода. О ней написано достаточно много книг, но всё же в теме есть пробелы. Например, те самые книги сфокусированы больше на советах КАК написать читабельный код, а не на причинах того, почему один код является хорошо читабельным, а другой — нет. Книга говорит нам «используйте подходящие названия переменных» — но что делает одно название более подходящим, чем другое? Работает ли это для всех примеров подобного кода? Работает ли это для всех программистов, которым попадётся на глаза этот код? Как раз о последнем я и хотел бы поговорить чуть детальнее. Давайте погрузимся немного в человеческую психику. Наш мозг — главный наш инструмент, хорошо бы изучить специфику его работы.
      Читать дальше →
    • Портируем код с Qt 1.0 на Qt 5.11

      • Перевод
      Недавно вышел Qt 5.11 и мне подумалось, что сейчас самое время обновить до него кое-какие мои проектики на Qt 1.0… Ладно, шучу :) На самом деле мне стало интересно, насколько хорошо за все эти годы развития фреймворка Qt нам удавалось сохранять обратную совместимость кода.

      Qt гарантирует совместимость на уровне кода и бинарников при обновлении между минорными версиями фреймворка (и мы серьёзно относимся к этому обещанию). Вы не должны переписывать (или даже перекомпилировать) свой код при переходе на другую минорную версию Qt. Однако переходы между мажорными версиями требовали от нас идти на некоторые жертвы ради прогресса. С релиза Qt 1.0 в 1996 году мы ломали совместимость кода четыре раза: в версиях 2.0, 3.0, 4.0 (ох, это было болезненно!) и 5.0.

      Мы старались даже в мажорных версиях сломать как можно меньше всего, но всё же это приходилось делать. Отсюда возникает вопрос: насколько сложно портировать приложение, написанное во времена Qt 1.0 до современного Qt 5.11?

      Для ответа на этот вопрос я взял пример кода, который поставлялся с документацией на Qt 1.0 и постарался собрать его с помощью Qt 5. Наши публичные архивы содержат изменения начиная с версии 1.41, так что мне пришлось изрядно покопаться в дрейнейшей истории, пройти через логи четырёх разных систем контроля версий… но это я уже отвлекаюсь. Проект, который я планирую собрать, называется «t14» — поскольку это иллюстрация к 14-ой (и последней) главе оригинального руководства.

      И вот, что мне пришлось проделать для его сборки.
      Читать дальше →
    • Полное руководство по стратегии обнаружения изменений Angular onPush

      • Перевод

      image


      Default cтратегия обнаружения изменений


      По умолчанию Angular использует ChangeDetectionStrategy.Default стратегию обнаружения изменений.


      ChangeDetectionStrategy.Default работает таким образом, что каждый раз, когда что-то меняется в нашем приложении, в результате различных пользовательских событий, таймеров, XHR, промисов и т.д., обнаружение изменений будет запускаться по всем компонентам.

      Читать дальше →
      • +19
      • 4,9k
      • 3
    • Сделаем Windows медленнее! Часть первая: файловый доступ

      • Перевод
      imageОС Windows долгое время попрекали за медлительность её файловых операций и медленное создание процессов. А почему бы не попробовать сделать их ещё более медленными? Эта статья покажет способы замедления файловых операций в Windows примерно в 10 раз от их нормальной скорости (или даже больше), причём способы эти практически не поддаются отслеживанию обычным пользователем.

      А ещё, конечно же, мы научимся подобные ситуации обнаруживать и исправлять. Весь текст написан на основе проблемы, с которой я столкнулся пару месяцев назад, так что всё, написанное ниже, полностью реально.
      Читать дальше →
      • +70
      • 35k
      • 9
    • Как передать полиморфный объект в алгоритм STL

      • Перевод
      Как мы можем прочесть в первой главе книги Effective C++, язык С++ является по сути своей объединением 4 разных частей:

      • Процедурная часть, доставшаяся в наследство от языка С
      • Объектно-ориентировання часть
      • STL, пытающийся следовать функциональной парадигме
      • Шаблоны

      Эти четыре, по сути, подъязыка составляют то, что мы называем единым языком С++. Поскольку все они объединены в одном языке, то это даёт им возможность взаимодействовать. Это взаимодействие порой порождает интересные ситуации. Сегодня мы рассмотрим одну из них — взаимодействие объектно-ориентированной модели и STL. Оно может принимать разнообразные формы и в данной статье мы рассмотрим передачу полиморфных функциональных объектов в алгоритмы STL. Эти два мира не всегда хорошо контачат, но мы можем построить между ними достаточно неплохой мостик.

      image
      Читать дальше →
      • +32
      • 7,7k
      • 8
    • Property Injection своими руками (Xamarin/.Net)

        В данной статье мы рассмотрим, чем отличается Property Injection от Constructor Injection и реализуем первое в дополнение к последнему на базе небольшого DI-контейнера в исходниках.

        Это обучающий материал начального уровня. Будет полезен тем, кто ещё не знаком с DI-контейнерами или интересуется, как оно устроено изнутри.
        Читать дальше →
        • +10
        • 3,1k
        • 5
      • Ускорение перечисления процессов и потоков в ОС Windows

          Иногда бывает нужно перечислить все процессы или потоки, которые в данный момент работают в ОС Windows. Это может понадобиться по разным причинам. Возможно, мы пишем системную утилиту вроде Process Hacker, а может быть мы хотим как-то реагировать на запуск/остановку новых процессов или потоков (писать лог, проверять их, внедрять в них свой код). Самым правильным способом это реализовать является, конечно же, написание драйвера. Там всё просто — используем PsSetCreateProcessNotifyRoutine и PsSetCreateThreadNotifyRoutine для установки колбек-функций, которые будут вызываться при запуске/остановке процессов и потоков. Работает очень быстро и не ест ресурсы. Именно так и делают все серьёзные инструменты. Но разрабатывать драйвера — не всегда подходящий способ. Их нужно уметь правильно писать, их с недавних пор обязательно нужно подписывать сертификатами (что не бесплатно) и регистрировать в Microsoft (что не быстро). И ещё их не удобно распространять — например, программы с ними нельзя выкладывать в Microsoft Store.

          Ну, давайте тогда пользоваться тем, что предлагает публичный WinAPI. А предлагает он функцию CreateToolhelp32Snapshot(), которую предлагается использовать как-то вот так. Всё, кажется, хорошо — есть информация о процессах, потоках. Немного расстраивает тот факт, что вместо элегантных колбеков мы вынуждены делать бесконечный пулинг в цикле, но это ладно.

          Самая большая проблема здесь — это производительность. Связка CreateToolhelp32Snapshot() + Process32First() + Process32Next() работает ну очень медленно. Возможно, проблема лежит где-то в той же области, что и описанная вот в этой статье проблема с Heap32First() + Heap32Next(). Кратко — в силу исторических причин кое-где проход по линейному списку занимает квадратичное время.

          Можно ли как-то всё это ускорить? Можно. Но придётся сойти со светлого пути использования одних лишь публичных функций WinAPI.
          Читать дальше →
          • +30
          • 15,3k
          • 5
        • Почему функция Heap32Next() работает так медленно на Windows 7?

          • Перевод
          Если вы занимаетесь системным программированием под Windows, то могли бы заметить, что весьма полезные функции Heap32First/Heap32Next и другие из того же семейства стали работать существенно медленнее начиная с Windows 7. Что же с ними случилось?

          Давайте перенесёмся в далёкий 1992 год. Разрабатывается Windows 3.1. Одним из новых компонентов в ней стал ToolHelp. Он позволил немного покопаться во внутренностях ядра ОС. Для нас в нём наиболее интересны функции, позволяющие просматривать данные в куче (heap). Поскольку Windows 3.1 использовала кооперативную многозадачность, вызывая подобные функции можно было быть уверенным в том, что содержимое кучи не изменится между вызовами HeapFirst и HeapNext, ведь у ОС не было права прервать выполнение процесса и переключить контекс на выполнение другого. Вот были времена!
          Читать дальше →
        • Баг компилятора? Линкера? Нет, баг ядра Windows

          • Перевод
          imageГейзенбаг — это худшее, что может произойти. В описанном ниже исследовании, которое растянулось на 20 месяцев, мы уже дошли до того, что начали искать аппаратные проблемы, ошибки в компиляторах, линкерах и делать другие вещи, которые стоит делать в самую последнюю очередь. Обычно переводить стрелки подобным образом не нужно (баг скорее всего у вас в коде), но в данном случае нам наоборот — не хватило глобальности виденья проблемы. Да, мы действительно нашли баг в линкере, но кроме него мы ещё нашли и баг в ядре Windows.

          В сентябре 2016 года мы стали замечать случайно происходящие ошибки при сборке Хрома — 3 билда из 200 провалились из-за крэша процесса protoc.exe. Это один из бинарников, который при сборке Хрома сначала собирается сам, а затем запускается для генерации заголовочных файлов других компонентов. Но вместо этого он падал с ошибкой «access violation».
          Читать дальше →
        • Зомби, которые съедают вашу память

          • Перевод
          • Tutorial
          Что бы вы там себе не думали, а зомби существуют. И они действительно едят мозги. Не человеческие, правда, а компьютерные. Я говорю сейчас о зомби-процессах и потребляемых ими ресурсах. Это будет душераздирающая история о потерянных и снова найденных 32 ГБ оперативной памяти. Возможно, лишь некоторые из вас столкнутся с точно такой же проблемой, но если вдруг это произойдёт — у вас хотя бы будет шанс понять, что происходит.

          Начнём с того, что компьютеры под управлением ОС Windows склонны со временем терять память. Ну, по крайней мере, у меня, при моём способе ими пользоваться. После пары недель без перезагрузок (или, например, всего одного уикэнда за который я 300 раз пересобрал Хром) я стал замечать, что диспетчер задач начинает показывать мне очень маленькое количество свободной оперативной памяти, но в то же время в системе нет никаких процессов, которые эту самую память активно используют. В том примере выше (с 300 сборками Хрома) диспетчер задач сказал мне, что в системе занято 49.8 ГБ плюс ещё 4.4 ГБ памяти сжато — но при этом запущено всего несколько процессов, и все они в сумме даже и близко не используют столько памяти:

          image

          В моём компьютере 96 ГБ оперативной памяти (да, я счастливчик) и когда у меня нет вообще никаких запущенных процессов — я, знаете ли, хотел бы видеть ну хотя бы половину этой памяти свободной. Я правда рассчитываю на это. Но иногда этого достичь не удаётся и мне приходится перезагружать ОС. Ядро Windows написано качественно и надёжно (без шуток), так что память не должна бы пропадать бесследно. Но всё же она пропадает.
          Читать дальше →
        • Эффективное преобразование данных с использованием трансдьюсеров

          • Перевод
          image


          Преобразование больших массивов данных может быть достаточно ресурсозатратным, особенно, когда вы используете функции высшего порядка, такие как map и filter.


          В этой статье мы покажем возможности преобразователей для создания эффективной функции трансформации данных, которые не создают временных массивов. Временные коллекции создаются для функций map и filter соединеных друг с другом. Это потому, что эти функции, возвращаясь к новой коллекции, выдают результат следующей функции.


          Представьте, что у вас база в 1000000 человек, и вам нужно создать сабсет “имен женщин старше 18 лет, которые живут в Нидерландах”. Существуют различные способы решения этой проблемы, но начну с цепочек.


          const ageAbove18 = (person) => person.age > 18;
          const isFemale = (person) => person.gender === ‘female’;
          const livesInTheNetherlands = (person) => person.country === ‘NL’;
          const pickFullName = (person) => person.fullName;
          const output = bigCollectionOfData
            .filter(livesInTheNetherlands)
            .filter(isFemale)
            .filter(ageAbove18)
            .map(pickFullName);

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


          image

          Конечно, отфильтрованные коллекции будут несколько сокращены, но это, все еще довольно затратно.


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

          Читать дальше →
          • +17
          • 4,8k
          • 7
        • Миром всё ещё управляет язык С

          • Перевод
          Многие из проектов на языке С, существующих сегодня, начинали разрабатываться ещё десятилетия назад. Операционная система UNIX стартовала 1969 году (и писалась на ассемблере), но уже в 1972 была переписана на С. Точнее, это язык С был создан для того, чтобы появилось что-то, на что было бы удобно переписать с ассемблера ядро UNIX и получить чуть более высокоуровневый код, менее зависимый от архитектуры и позволяющий выполнять больше полезной работы на каждую строчку написанного кода.

          Разработка базы данных Oracle началась в 1977 году (тоже на ассемблере) и тоже была переписана на С в 1983 году. К тому времени это был уже один из самых популярных языков в мире.

          В 1985 году вышла Windows 1.0. Хотя код операционной системы Windows не является открытым, общеизвестно, что ядро в основном написано на С с небольшими вставками ассемблера. Разработка Linux началась в 1991 году и началась сразу на С. В следующем году она была опубликована под лицензией GPL и использована как часть GNU Operating System, которая и сама начиналась как проект на С и Lisp, так что многие компоненты были написаны на С.

          Но проекты на С — это не только то, что стартовало десятилетия назад, когда выбор языков, скажем прямо, был достаточно ограничен. Много С-кода пишется и сейчас, на нём начинаются и новые проекты. Для этого есть причины.

          Как именно язык С управляет миром?

          Читать дальше →
        • Выравнивание инструкций кода

          • Перевод
          Насколько трудно может быть измерить производительность простой функции, вроде вот этой?

          // func.cpp
          void benchmark_func(int* a)
          {
          	for (int i = 0; i < 32; ++i)
          		a[i] += 1;
          }

          Ну, давайте просто завернём её в какой-нибудь микробенчмарк, вызовем её много-много раз (для усреднения результатов) и посмотрим, что получится, да? Ну ладно, мы можем ещё посмотреть на сгенерированные инструкции просто чтобы убедиться, что компилятор чего-то там не «наоптимизировал». Мы можем также провести несколько разных тестов, чтобы убедиться, что именно цикл является узким местом. Ну и всё. Мы понимаем, что мы измеряем, да?

          Давайте представим, что в нашем файле есть ещё одна функция, скорость работы который вы тоже замеряете, но в отдельных тестах. Т.е. файл выглядит как-то так:

          // func.cpp
          void foo(int* a)
          {
          	for (int i = 0; i < 32; ++i)
          		a[i] += 1;
          }
          
          void benchmark_func(int* a)
          {
          	for (int i = 0; i < 32; ++i)
          		a[i] += 1;
          }

          И вот однажды ваш менеджер приходит к вам и показывает претензию от пользователя вашей библиотеки, которая заключается в том, что она не работает настолько быстро, как вы обещали. Но постойте, мы ведь хорошо измерили производительность и обещали ровно то, что получили по результатам тестов. Что же пошло не так?
          Читать дальше →
        • 5 тенденций развития микросервисов в 2018 году

          • Перевод
          image

          2017 год стал важным годом для DevOps, поскольку число игроков в экосистеме существенно выросло, а количество проектов с CNCF утроилось. Глядя на год вперед, мы ожидаем, что инновации и рыночные изменения ускорятся еще больше. Ниже мы рассмотрели тенденции в области микросервисов в 2018 году: сервисные связки(так называемые “меши”), event-driven архитектуры, нативная безопасность контейнеров, GraphQL и Chaos инженерия.

          1. Сервисные связки популярны!


          Сервисные связки или “меши”, выделенный уровень инфраструктуры для улучшения связи между сервисами, в настоящее время наиболее обсуждаема в контексте облачности. По мере того, как контейнеры становятся более распространенными, топологии сервисов становится все более динамичными, требуя улучшеной функциональности сети. Сервисные связки могут помочь управлять трафиком через обнаружение сервисов, маршрутизацию, балансировку нагрузки, проверку работоспособности и наблюдаемость(observability). Сервисные связки пытаются укротить непоколебимую сложность контейнера.

          Очевидно, что сервисные сетки становятся все более популярными, поскольку балансировщики нагрузки, такие как HAProxy, traefik и NGINX, начали перестраиваться и представлять себя как плоскости данных(data planes). Мы пока не видели широкомасштабного развертывания, но мы знаем о компаниях, которые уже используют связки на живых серверах, в “продакшене”, так сказать. Кроме того, сервисные связки не являются эксклюзивными для микросервисов или сред Kubernetes, и также могут применяться в среде VM и без сервера. Например, в Национальном Центре Биотехнологической Информации(NCBI) нет контейнеров, но используется Linkerd.
          Читать дальше →
          • +12
          • 10,7k
          • 2
        • Прошлое, настоящее и будущее технологий распознавания речи

          • Перевод
          image

          Голос — это будущее. Мировые технологические гиганты требуют жизненно важной доли рынка, а ComScore прогнозирует, что «до 50% всех поисковых запросов будут выполняться голосом уже к 2020 году».

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

          История технологии распознавания речи


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

          Наше восхищение является инстинктивным: мы очарованы машинами, которые могут понять нас.

          С антропологической точки зрения, мы разработали произносимое слово задолго до его письменного аналога, и мы можем говорить по 150 слов в минуту, по сравнению с ничтожными 40 словами, которые среднестатистический человек может написать за 60 секунд.

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

          История технологии показывает, что распознавание речи далеко не новая озабоченность, даже если темпы развития не всегда соответствовали уровню интереса к этой теме. Как мы видим впоследствии, крупные прорывы, относящиеся к XVIII веку, обеспечили платформу для цифровых помощников, о которых мы все сегодня знаем.
          Читать дальше →
        • Аутентификация в мобильных приложениях

            История с предысторией


            Идеальный телефон, как верный пёс, должен узнавать хозяина по запаху и охранять имущество от посторонних.

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

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

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

            Скоро этого стало не хватать. У первобытных программистов появились идентификаторы, затем логин с паролем – и вот перед нами классическая Basic Authentication протокола HTTP.
            Читать дальше →
          Самое читаемое