Какую самую нелепую пессимизацию вы видели?

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

42 ответа

Решение

В старом проекте мы унаследовали некоторые (в остальном отличные) программисты встраиваемых систем, которые имели большой опыт работы с Z-8000.

Нашей новой средой был 32-битный Sparc Solaris.

Один из парней пошел и заменил все целые числа на шорты, чтобы ускорить наш код, поскольку захват 16 битов из оперативной памяти был быстрее, чем захват 32 битов.

Мне пришлось написать демонстрационную программу, чтобы показать, что захват 32-битных значений в 32-битной системе быстрее, чем захват 16-битных значений, и объяснить, что для получения 16-битного значения процессор должен был иметь 32-битную ширину. доступ к памяти, а затем замаскировать или сдвинуть биты, не необходимые для 16-битного значения.

Я думаю, что фраза "преждевременная оптимизация - корень всего зла" - это путь, путь использованный. Для многих проектов это стало поводом не принимать во внимание производительность до поздней стадии проекта.

Эта фраза часто является опорой для людей, чтобы избежать работы. Я вижу эту фразу, когда люди действительно должны сказать: "Ну и дела, мы действительно не думали об этом заранее, и у нас нет времени, чтобы разобраться с этим сейчас".

Я видел гораздо больше "нелепых" примеров глупых проблем с производительностью, чем примеров проблем, вызванных "пессимизацией"

  • Чтение одного и того же ключа реестра тысячи (или десятки тысяч) раз при запуске программы.
  • Загрузка одной и той же DLL сотни или тысячи раз
  • Тратить мегабайты памяти, сохраняя полный путь к файлам без необходимости
  • Не организовывать структуры данных, чтобы они занимали больше памяти, чем им нужно
  • Определение размера всех строк, в которых хранятся имена файлов или пути к MAX_PATH
  • Бесплатный опрос для вещи, которая имеет события, обратные вызовы или другие механизмы уведомления

Я думаю, что лучше сказать следующее: "Оптимизация без измерения и понимания вовсе не является оптимизацией - это просто случайное изменение".

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

Базы данных являются пессимизацией игровых площадок.

Избранное включает в себя:

  • Разбейте таблицу на несколько (по диапазону дат, алфавитному диапазону и т. Д.), Потому что он "слишком большой".
  • Создайте архивную таблицу для удаленных записей, но продолжайте объединять ее с рабочей таблицей.
  • Дублировать целые базы данных по (подразделение / клиент / продукт / и т. Д.)
  • Не добавляйте столбцы в индекс, потому что он слишком велик.
  • Создайте много сводных таблиц, потому что пересчет из необработанных данных выполняется слишком медленно.
  • Создайте столбцы с подполями для экономии места.
  • Денормализовать в поля как массив.

Это с моей головы.

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

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

С другой стороны, наши разработчики программного обеспечения решили, что распакованные данные должны быть отформатированы в очень читаемый XML-документ и сохранены в нашей базе данных как таковой (в отличие от хранения каждого поля в соответствующем столбце). Их идея заключалась в том, что "XML - это будущее", "дисковое пространство дешевое" и "процессор дешевый", поэтому не нужно было ничего оптимизировать. В результате наши 16-байтовые пакеты были превращены в документы размером 2 КБ, хранящиеся в одном столбце, и даже для простых запросов нам пришлось загружать мегабайты документов XML в память! Мы получали более 50 пакетов в секунду, поэтому вы можете себе представить, насколько ужасной стала производительность (кстати, компания обанкротилась).

Итак, еще раз, нет абсолютного правила. Да, иногда слишком ранняя оптимизация является ошибкой. Но иногда девиз "процессор / дисковое пространство / память дешев" - настоящий корень всего зла.

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

Вот недавний пример:

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

Я: Почему вы рассматриваете это? Какую проблему вы пытаетесь решить?

Он: Таблица X слишком широка, мы разбиваем ее по соображениям производительности.

Я: Что заставляет вас думать, что оно слишком широкое?

Он: Консультант сказал, что в одной таблице слишком много столбцов.

Я: И это влияет на производительность?

Он: Да, пользователи сообщают о периодических замедлениях в модуле XYZ приложения.

Я: Откуда вы знаете, что ширина таблицы является источником проблемы?

Он: Это таблица ключей, используемая модулем XYZ, и она похожа на 200 столбцов. Это должно быть проблемой.

Я (Объяснение): Но модуль XYZ, в частности, использует большинство столбцов в этой таблице, и столбцы, которые он использует, непредсказуемы, поскольку пользователь настраивает приложение для отображения данных, которые он хочет отобразить из этой таблицы. Вполне вероятно, что в 95% случаев мы все равно будем объединять все столы, что ухудшит производительность.

Он: Консультант сказал, что он слишком широкий, и нам нужно его изменить.

Я: Кто этот консультант? Я не знал, что мы наняли консультанта, и они вообще не разговаривали с командой разработчиков.

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

Я: Ага. Поэтому консультант, который продает услуги по перепроектированию базы данных, считает, что нам нужно перепроектировать базу данных....

Разговор продолжался и продолжался вот так. После этого я еще раз взглянул на данную таблицу и определил, что ее можно сузить с помощью простой нормализации без необходимости использования экзотических стратегий разбиения. Это, конечно, оказалось спорным вопросом, как только я исследовал проблемы с производительностью (ранее не сообщавшиеся) и выявил их по двум факторам:

  1. Отсутствуют индексы по нескольким ключевым столбцам.
  2. Несколько мошеннических аналитиков данных, которые периодически блокировали таблицы ключей (включая "слишком широкую"), обращаясь непосредственно к производственной базе данных с помощью MSAccess.

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

Я видел людей, использующих alphadrive-7 для полной инкубации CHX-LT. Это необычная практика. Более распространенной практикой является инициализация ZT-трансформатора, чтобы уменьшить буферизацию (из-за большей устойчивости к перегрузке) и создать байтовую символику в стиле Java.

Абсолютно пессимистично!

Признаюсь, ничего страшного, но я поймал людей, использующих StringBuffer для объединения строк вне цикла в Java. Это было что-то простое, как поворот

String msg = "Count = " + count + " of " + total + ".";

в

StringBuffer sb = new StringBuffer("Count = ");
sb.append(count);
sb.append(" of ");
sb.append(total);
sb.append(".");
String msg = sb.toString();

Раньше было довольно распространенной практикой использовать технику в цикле, потому что она была заметно быстрее. Дело в том, что StringBuffer синхронизирован, так что на самом деле есть дополнительные издержки, если вы объединяете только несколько строк. (Не говоря уже о том, что различие в этой шкале абсолютно тривиально.) Два других момента об этой практике:

  1. StringBuilder не синхронизирован, поэтому предпочтительнее, чем StringBuffer, в тех случаях, когда ваш код не может быть вызван из нескольких потоков.
  2. Современные компиляторы Java превратят удобочитаемую конкатенацию строк в оптимизированный байт-код для вас, когда это будет необходимо.

Однажды я увидел базу данных MSSQL, в которой использовалась таблица "Root". Корневая таблица имела четыре столбца: GUID (уникальный идентификатор), ID (int), LastModDate (datetime) и CreateDate (datetime). Все таблицы в базе данных были Внешним Ключом к Корневой таблице. Всякий раз, когда в какой-либо таблице в БД создавалась новая строка, вам приходилось использовать пару хранимых процедур для вставки записи в корневую таблицу, прежде чем вы могли бы перейти к фактической таблице, которая вам нужна (вместо того, чтобы база данных выполняла работу для Вы с несколькими триггерами простых триггеров).

Это создавало беспорядок бесполезных подслушиваний и головных болей, требовало, чтобы все, что было написано поверх него, использовало sprocs (и устраняло мои надежды представить LINQ для компании. Это было возможно, но просто не стоило головной боли), и завершить это не было даже не выполнить то, что предполагалось.

Разработчик, выбравший этот путь, защитил его, предполагая, что это сэкономило тонны пространства, потому что мы не использовали Guids для самих таблиц (но... не генерируется ли GUID в таблице Root для каждой строки, которую мы создаем?) каким-то образом повысил производительность и упростил аудит изменений в базе данных.

О, и диаграмма базы данных выглядела как паук-мутант из ада.

Как насчет POBI - пессимизация, очевидно, по намерению?

Моя коллега в 90-х устала от того, что генеральный директор пнул ее в задницу только потому, что генеральный директор провел первый день каждого выпуска программного обеспечения ERP (пользовательского) с поиском проблем с производительностью в новых функциях. Даже если новые функциональные возможности сокращали гигабайты и делали невозможное возможным, он всегда находил какие-то детали или даже, казалось бы, серьезную проблему, чтобы скулить. Он считал, что знает много о программировании и получил свои удары ногами программиста.

Из-за некомпетентного характера критики (он был генеральным директором, а не ИТ-специалистом), моему коллеге так и не удалось сделать это правильно. Если у вас нет проблемы с производительностью, вы не можете ее устранить...

Вплоть до одного выпуска он поместил много вызовов функции Delay (200) (это был Delphi) в новый код. Прошло всего 20 минут после начала работы, и ему было приказано явиться в офис генерального директора, чтобы лично принести ему запоздалые оскорбления.

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

Естественно, мой коллега теперь отдыхал в течение одного или двух дней за его столом, улучшая свои навыки прицеливания в Quake - затем на второй или третий день он удалил вызовы задержки, восстановил и выпустил "экстренный патч", о котором он распространял слово что он потратил 2 дня и 1 ночь, чтобы исправить дыры в производительности.

Это был первый (и единственный) раз, когда злой генеральный директор сказал "отличная работа!" Для него. Это все, что имеет значение, верно?

Это было настоящее ПОБИ.

Но это также своего рода оптимизация социального процесса, так что все в порядке.

Я думаю.

var stringBuilder = new StringBuilder();
stringBuilder.Append(myObj.a + myObj.b + myObj.c + myObj.d);
string cat = stringBuilder.ToString();

Лучшее использование StringBuilder, которое я когда-либо видел.

"База данных независимости". Это означало отсутствие хранимых процедур, триггеров и т. Д. - даже никаких внешних ключей.

Использование регулярного выражения для разделения строки, когда достаточно простого string.split

Очень поздно к этой теме я знаю, но я видел это недавно:

bool isFinished = GetIsFinished();

switch (isFinished)
{
    case true:
        DoFinish();
        break;

    case false:
        DoNextStep();
        break;

    default:
        DoNextStep();
}

Знаете, на случай, если логическое значение имеет некоторые дополнительные значения...

Кажется, никто не упомянул сортировку, так что я буду.

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

Худший пример, который я могу вспомнить, - это внутренняя база данных в моей компании, содержащая информацию обо всех сотрудниках. Он получает еженедельное обновление от HR и имеет веб-сервис ASP.NET на вершине. Многие другие приложения используют веб-сервис для заполнения таких вещей, как поля поиска / раскрывающегося списка.

Пессимизм заключается в том, что разработчик считал, что повторные вызовы веб-службы будут слишком медленными для выполнения повторных запросов SQL. И что он сделал? Событие запуска приложения считывает всю базу данных и преобразует все это в объекты в памяти, которые хранятся неопределенно долго, пока пул приложений не будет перезагружен. Этот код был настолько медленным, что его загрузка заняла менее 15 минут у менее чем 2000 сотрудников. Если вы случайно переработали пул приложений в течение дня, это может занять 30 минут или более, поскольку каждый запрос веб-службы будет запускать несколько одновременных перезагрузок. По этой причине новые сотрудники не будут появляться в базе данных в первый день, когда была создана их учетная запись, и, следовательно, не смогут получить доступ к большинству внутренних приложений в первые пару дней, трясясь пальцами.

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

Однажды я работал над приложением, которое было полно кода, подобного этому:

 1 tuple *FindTuple( DataSet *set, int target ) {
 2     tuple *found = null;
 3     tuple *curr = GetFirstTupleOfSet(set);
 4     while (curr) {
 5         if (curr->id == target)
 6             found = curr;
 7         curr = GetNextTuple(curr);
 8     }
 9     return found;
10 }

Просто удаляя found, возвращаясь null в конце и изменив шестую строку на:

            return curr;

Удвоил производительность приложения.

Однажды мне пришлось попытаться изменить код, который включал эти драгоценные камни в класс констант

public static String COMMA_DELIMINATOR=",";
public static String COMMA_SPACE_DELIMINATOR=", ";
public static String COLIN_DELIMINATOR=":";

Каждый из них использовался несколько раз в остальной части приложения для различных целей. COMMA_DELIMINATOR замусорил код с более чем 200 использованиями в 8 различных пакетах.

Большое все время номер один, с которым я сталкиваюсь снова и снова в собственных программах:

Не использовать функции СУБД по причинам "переносимости", потому что "мы можем захотеть переключиться на другого поставщика позже".

Читай по губам. Для любой внутренней работы: ЭТОГО НЕ БУДЕТ!

У меня был сотрудник, который пытался перехитрить наш оптимизатор компилятора Си и регулярно переписывал код, который мог прочитать только он. Одним из его любимых приемов было изменение читабельного метода, например (составление кода):

int some_method(int input1, int input2) {
    int x;
    if (input1 == -1) {
        return 0;
    }
    if (input1 == input2) {
        return input1;
    }
    ... a long expression here ...
    return x;
}

в это:

int some_method() {
    return (input == -1) ? 0 : (input1 == input2) ? input 1 :
           ... a long expression ...
           ... a long expression ...
           ... a long expression ...
}

То есть первая строка метода, который когда-то читается return "и вся остальная логика будет заменена глубоко вложенными троичными выражениями. Когда вы пытались спорить о том, как это было неосуществимо, он указывал на тот факт, что выходные данные сборки его метода были на три или четыре инструкции по сборке короче. обязательно немного быстрее, но всегда немного короче. Это была встроенная система, в которой время от времени имело значение использование памяти, но можно было сделать гораздо более простые оптимизации, чем те, которые сделали бы код читабельным.

Затем, после этого, по какой-то причине он решил, что ptr->structElement было слишком нечитабельно, поэтому он начал менять все это на (*ptr).structElement на теории, что это было более читабельным и быстрее.

Превращение читаемого кода в нечитаемый код для улучшения не более чем на 1%, а иногда и на самом деле более медленный код.

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

Пока я копался, я обнаружил, что оригинальный программист стремился ускорить процесс, распараллеливая анализ - запуская новый поток для каждого дополнительного источника данных. Однако он допустил ошибку в том, что все потоки требовали общего ресурса, на котором они находились в тупике. Конечно, все преимущества параллелизма исчезли. Более того, большинство систем рухнуло, чтобы запустить более 100 потоков только для блокировки всех, кроме одной. Моя мощная девайс-машина была исключением из-за того, что она прошла через набор из 150 источников примерно за 6 часов.

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

Я полагаю, я мог бы предложить этот драгоценный камень:

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1, root = 0;
    #define ISQRT_INNER(shift) \
    { \
        if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \
        { \
            root += 1 << shift; \
            value -= tmp; \
        } \
    }

    // Find out how many bytes our value uses
    // so we don't do any uneeded work.
    if (value & 0xffff0000)
    {
        if ((value & 0xff000000) == 0)
            tmp = 3;
        else
            tmp = 4;
    }
    else if (value & 0x0000ff00)
        tmp = 2;

    switch (tmp)
    {
        case 4:
            ISQRT_INNER(15);
            ISQRT_INNER(14);
            ISQRT_INNER(13);
            ISQRT_INNER(12);
        case 3:
            ISQRT_INNER(11);
            ISQRT_INNER(10);
            ISQRT_INNER( 9);
            ISQRT_INNER( 8);
        case 2:
            ISQRT_INNER( 7);
            ISQRT_INNER( 6);
            ISQRT_INNER( 5);
            ISQRT_INNER( 4);
        case 1:
            ISQRT_INNER( 3);
            ISQRT_INNER( 2);
            ISQRT_INNER( 1);
            ISQRT_INNER( 0);
    }
#undef ISQRT_INNER
    return root;
}

Поскольку квадратный корень был рассчитан в очень чувствительном месте, я получил задачу найти способ сделать его быстрее. Этот небольшой рефакторинг сократил время выполнения на треть (для комбинации аппаратного обеспечения и используемого компилятора, YMMV):

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1, root = 0;
    #define ISQRT_INNER(shift) \
    { \
        if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \
        { \
            root += 1 << shift; \
            value -= tmp; \
        } \
    }

    ISQRT_INNER (15);
    ISQRT_INNER (14);
    ISQRT_INNER (13);
    ISQRT_INNER (12);
    ISQRT_INNER (11);
    ISQRT_INNER (10);
    ISQRT_INNER ( 9);
    ISQRT_INNER ( 8);
    ISQRT_INNER ( 7);
    ISQRT_INNER ( 6);
    ISQRT_INNER ( 5);
    ISQRT_INNER ( 4);
    ISQRT_INNER ( 3);
    ISQRT_INNER ( 2);
    ISQRT_INNER ( 1);
    ISQRT_INNER ( 0);

#undef ISQRT_INNER
    return root;
}

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

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

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1 << 30, root = 0;

    while (tmp != 0)
    {
        if (value >= root + tmp) {
            value -= root + tmp;
            root += tmp << 1;
        }
        root >>= 1;
        tmp >>= 2;
    }

    return root;
}

Это точно такой же алгоритм, хотя и немного другая реализация, поэтому я полагаю, что он подходит.

Это может быть на более высоком уровне, чем то, что вы хотели, но исправление (если вам позволено) также включает больший уровень боли:

Настаивайте на том, чтобы вручную запустить Диспетчер объектных отношений / Уровень доступа к данным вместо использования одной из установленных, проверенных, зрелых библиотек (даже после того, как они были вам указаны).

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

Перед КАЖДОЙ операцией JavaScript проверяется, существует ли объект, с которым вы работаете.

if (myObj) { //or its evil cousin, if (myObj != null) {
    label.text = myObj.value; 
    // we know label exists because it has already been 
    // checked in a big if block somewhere at the top
}

Моя проблема с этим типом кода - никого не волнует, что если его не существует? Просто ничего не делать? Не дать отзыв пользователю?

Я согласен, что Object expected ошибки раздражают, но это не лучшее решение для этого.

Это не совсем подходит к вопросу, но я все равно упомяну об этом как предостерегающую историю. Я работал над распределенным приложением, которое работало медленно, и прилетел в округ Колумбия, чтобы присутствовать на совещании, в первую очередь направленном на решение проблемы. Руководитель проекта начал обрисовывать реструктуризацию, направленную на устранение задержки. Я вызвалась, что в выходные я провела некоторые измерения, которые изолировали узкое место от одного метода. Оказалось, что при локальном поиске отсутствовала запись, из-за которой приложению приходилось переходить на удаленный сервер при каждой транзакции. Добавив запись обратно в локальное хранилище, задержка была устранена - проблема решена. Обратите внимание, что перестройка не решит проблему.

Как насчет ЯГНИ, экстремизм. Это форма преждевременной пессимизации. Кажется, что каждый раз, когда вы применяете YAGNI, вам это в конечном итоге понадобится, что в 10 раз увеличит ваши усилия по добавлению, чем если бы вы добавили его в начале. Если вы создадите успешную программу, то, скорее всего, вам это нужно. Если вы привыкли создавать программы, жизнь которых заканчивается быстро, продолжайте практиковать ЯГНИ, потому что тогда я полагаю, ЯГНИ.

Не совсем преждевременная оптимизация - но, безусловно, ошибочная - это было прочитано на сайте BBC, из статьи, обсуждающей Windows 7.

Г-н Керран сказал, что команда Microsoft Windows тщательно изучала все аспекты операционной системы, чтобы внести улучшения. "Мы смогли сократить время выключения на 400 миллисекунд, слегка подрезав музыку выключения WAV-файла.

Сейчас я еще не пробовал Windows 7, поэтому могу ошибаться, но готов поспорить, что есть и другие проблемы, которые важнее, чем время, необходимое для завершения работы. В конце концов, когда я вижу сообщение "Завершение работы Windows", монитор выключается, и я ухожу - как мне помогают эти 400 миллисекунд?

Кто-то в моем отделе однажды написал строковый класс. Интерфейс как CString, но без зависимости Windows.

Одна "оптимизация", которую они сделали, состояла в том, чтобы не выделять больше памяти, чем необходимо. Видимо, не понимая, что причина классов, как std::string выделить избыточную память так, чтобы последовательность += Операции могут выполняться за O(N) времени.

Вместо этого каждый += вызов вызвал перераспределение, которое превратило повторное добавление в алгоритм Шлеймеля-живописца O(n²).

Моему бывшему сотруднику (собственно говоря) было поручено создать новый модуль для нашей Java ERP, который должен был собирать и анализировать данные клиентов (розничная торговля). Он решил разделить поле КАЖДЫЙ Календарь / Дата / время на его компоненты (секунды, минуты, часы, день, месяц, год, день недели, биместер, триместр (!)), Потому что "как еще мне запросить" каждый понедельник "?"

while true; do echo 3 > /proc/sys/vm/drop_caches; sleep 3600; done

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

Другие вопросы по тегам