Почему трудно обеспечить эффективность при использовании библиотек?

datascience.stackexchange https://datascience.stackexchange.com/questions/138

  •  16-10-2019
  •  | 
  •  

Вопрос

Любая небольшая обработка базы данных может быть легко выполнена с помощью Python / Perl /...скрипты, использующие библиотеки и / или даже утилиты из самого языка.Однако, когда дело доходит до производительности, люди склонны обращаться к C / C ++ / языкам низкого уровня.Возможность адаптации кода к потребностям, по-видимому, и делает эти языки такими привлекательными для BigData - будь то в отношении управления памятью, параллелизма, доступа к диску или даже низкоуровневой оптимизации (с помощью сборочных конструкций на уровне C / C ++).

Конечно, такой набор преимуществ не обошелся бы без затрат:написание кода, а иногда даже изобретая велосипед заново, может быть довольно дорогим / утомительным.Хотя доступно множество библиотек, люди склонны писать код самостоятельно, когда им это необходимо грант Производительность.Что отключает утверждения о производительности при использовании библиотек при обработке больших баз данных?

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

Одним выстрелом:

  • что делает самостоятельное написание кода гарантия о производительности?
  • почему это рискованный полагаться на фреймворки / библиотеки, когда вам необходимо уверять высокая производительность?
Это было полезно?

Решение

После того как я сам снова и снова переписывал игру (и продолжаю это делать), моей немедленной реакцией было адаптивность.

В то время как фреймворки и библиотеки обладают огромным арсеналом (возможно, взаимозаменяемых) подпрограмм для стандартных задач, их свойство framework часто (всегда?) запрещает ярлыки.Фактически, большинство фреймворков имеют своего рода базовую инфраструктуру, вокруг которой реализован базовый уровень функциональности.Более специфическая функциональность использует базовый слой и размещена во втором слое вокруг ядра.

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

Теперь ваша отрасль меняет формат временной метки по умолчанию по очень веской причине (в моем случае они перешли со времени unix на время GPS).Если ваш фреймворк не является отраслевым, маловероятно, что они захотят изменить основное представление времени, поэтому в конечном итоге вы будете использовать фреймворк, который почти делает то, что ты хочешь.Каждый раз, когда вы получаете доступ к своим данным, вы должны сначала преобразовать их в формат отраслевого времени, и каждый раз, когда вы хотите их изменить, вы должны преобразовать их обратно в то, что ядро сочтет нужным.Вы не сможете передавать данные прямо из источника в приемник без двойного преобразования.

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

Со временем несоответствие между реальным миром и моделью будет нарастать.Имея готовый фреймворк, вы вскоре столкнулись бы с такими вопросами, как:Как я могу представлять this в that или как сделать рутину X принимать/производить Y.

До сих пор речь шла не о C / C ++.Но если по какой-то причине вы не можете изменить фреймворк, т.е.вам действительно приходится мириться с двойным преобразованием данных для перехода с одного конца на другой, тогда вы обычно используете что-то, что минимизирует дополнительные накладные расходы.В моем случае конвертер TAI-> UTC или UTC-> TAI лучше оставить для raw C (или FPGA).Здесь невозможна элегантность, нет глубокой продуманной структуры данных, которая делала бы проблему тривиальной.Это просто скучный оператор switch, и почему бы не использовать язык, компиляторы которого хороши в оптимизации именно этого?

Другие советы

Я не думаю, что все достигают C/C ++, когда производительность является проблемой.

Преимущество написания низкоуровневого кода использует меньше циклов ЦП, а иногда и меньше памяти. Но я бы отметил, что языки более высокого уровня могут вызвать языки более низкого уровня и сделать, чтобы получить часть этого значения. Языки Python и JVM могут сделать это.

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

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

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

Также обычно верно, что время разработчика и ошибки, стоимость которых загружается больше, чем новое оборудование. Год времени старшего разработчика может составить 200 тысяч долларов полностью загружены; Более года, это также арендует сотни серверов на расчеты. В большинстве случаев это может не иметь смысла беспокоиться о том, чтобы оптимизировать, что бросает больше оборудования.

Я не понимаю последующего наблюдения о «гранте» и «отключении» и «утверждении»?

Как все, что мы знаем, в цифровом мире есть много способов выполнить одну и ту же работу / получить ожидаемые результаты.

И обязанности / риски, которые поступают из кода, находятся на плечах разработчиков.

Это маленькое, но я думаю, очень полезный пример из мира .NET ..

Так много разработчиков .NET используют встроенный BinaryReader - BinaryWriter в их сериализации данных для производительности / Получить контроль над процессом.

Это исходный код CSHARP встроенной структуры в классе BinaryWriter 'Один из перегруженных методов записи:

// Writes a boolean to this stream. A single byte is written to the stream
// with the value 0 representing false or the value 1 representing true.
// 
public virtual void Write(bool value) 
{
     //_buffer is a byte array which declared in ctor / init codes of the class
    _buffer = ((byte) (value? 1:0));

    //OutStream is the stream instance which BinaryWriter Writes the value(s) into it.
    OutStream.WriteByte(_buffer[0]);
}

Как вы видите, этот метод мог бы записан без дополнительной назначения переменной _buffer:

public virtual void Write(bool value) 
{
    OutStream.WriteByte((byte) (value ? 1 : 0));
}

Без назначения мы могли бы получить несколько миллисекундов. Эти немногие миллисекунд могут принять как «почти ничего», но что, если есть много тысяч написания (т.е. в серверном процессе)?

Предположим, что «немногие» составляют 2 (миллисекунд), а много тысяч экземпляров-всего 2,000 .. Это означает, что на 4 секунды больше времени процесса. 4 секунды, возвращаясь.

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

Любой момент из источника BCL нормально, что вы видите, что разработчик решил использовать цикл () или Foreach (), которые могут реализовать цикл () в своем коде.

Эта небольшая выгода дает нам общую производительность ..

И если мы вернемся к методу BinaryWriter.Write () ..

На самом деле дополнительное назначение реализации _buffer не является ошибкой разработчика. Это точно решает «остаться в безопасности»!

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

Если разработчик решает «оставаться в безопасности», то обычно это означает, что затраты на производительность зависит от реализации «оставаться в безопасном» механизме.

Но если разработчик решит «стать рискованным, повысить производительность», это также не вина ... и есть некоторые обсуждения о «рискованном» кодировании.

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

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

Производительность обычно ценится в вторичных конкурентных библиотеках. «Библиотека X лучше, потому что она быстрее». Даже тогда очень часто эти библиотеки будут обменять самое оптимальное решение для одного, которое можно широко использовать.

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с datascience.stackexchange
scroll top