Производительность языков C ++ и виртуальных машин в высокочастотных финансах - PullRequest
31 голосов
/ 04 июля 2010

Я думал, что вопрос о производительности C / C ++ и C # / Java был задуман, и это означало, что я прочел достаточно доказательств, чтобы предположить, что языки виртуальных машин не обязательно медленнее, чем языки "почти кремний" Главным образом потому, что JIT-компилятор может выполнять оптимизации, которые статически скомпилированные языки не могут.

Однако недавно я получил резюме от парня, который утверждает, что высокочастотная торговля на основе Java всегда побеждена C ++ и что он был в такой ситуации.

Быстрый просмотр рабочих мест действительно показывает, что кандидаты HFT нуждаются в знании C ++, а на форуме Wilmott видно, что все практикующие говорят о C ++.

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

Возможно, эти парни пишут критические биты на C ++ и вызывают их из управляемой среды (P / Invoke и т. Д.)? Это возможно?

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

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

EDIT

Правильно, пара хороших ответов на данный момент, но довольно общие (хорошо протоптанные земли). Позвольте мне указать, какую программу будут запускать парни HFT.

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

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

Эти фирмы, как правило, не имеют ограничений относительно стоимости оборудования.

Ответы [ 15 ]

36 голосов
/ 06 июля 2010

Во-первых, 1 мс - это вечность в HFT. Если вы думаете, что это не так, было бы хорошо, чтобы немного больше читать о домене. (Это все равно, что быть в 100 милях от обмена.) Пропускная способность и задержка глубоко переплетены, как скажут формулы из любого учебника по теории элементарных очередей. В тех же формулах будут отображаться значения джиттера (часто преобладает стандартное отклонение задержки в очереди ЦП, если структура сети правильная, и вы не настроили достаточно ядер).

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

Вам не нужны позиции, если ваша стратегия не предсказывает (ОЧЕНЬ в ближайшей перспективе !!!) будущее (и это, хотите верьте, хотите нет, сделано ОЧЕНЬ успешно). Если вы находитесь на расстоянии 1 мс от обмена, то значительная часть ваших заказов не будет выполнена, и то, что вы хотели, будет снято. Скорее всего, те, кто выполнил одну ногу, в конечном итоге проигрывают или, по крайней мере, не приносят прибыли.

Какой бы ни была ваша стратегия ради аргумента, допустим, что в итоге соотношение выигрыша / проигрыша составляет 55% / 45%. Даже небольшое изменение отношения выигрыша / проигрыша может привести к значительному изменению прибыльности.

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

Существует высокая вариабельность скоростей, наблюдаемых в любую секунду. Я приведу пример. В некоторых из моих тестов я смотрю на 7 внебиржевых акций (CSCO, GOOG, MSFT, EBAY, AAPL, INTC, DELL) в середине дня ставки в секунду для этого потока могут варьироваться от 0 м / с (очень очень редко) до почти 2000 кавычек и сделок в пиковую секунду. (см., почему я думаю, что 20000 выше низок.)

Я создаю инфраструктуру и программное обеспечение для измерений для этого домена, и цифры, о которых мы говорим, составляют 100000 и миллионы в секунду. У меня есть библиотеки инфраструктуры производителя / потребителя C ++, которые могут передавать почти 5000000 (5 миллионов) сообщений в секунду между производителем и потребителем (32-битные ядра 2,4 ГГц). Это 64-байтовые сообщения с new, конструкцией, постановкой в ​​очередь, синхронизацией на стороне производителя и синхронизацией, удалением из очереди, касанием каждого байта, запуском виртуального деструктора, свободными на стороне потребителя. По общему признанию, это простой тест без Socket IO (и сокет IO может быть некрасивым), как это было бы в конечных точках конечных этапов конвейера. Это ВСЕ пользовательские классы синхронизации, которые синхронизируются только когда они пусты, пользовательские распределители, настраиваемые блокировки свободных очередей и списков, случайные STL (с настраиваемыми распределителями), но чаще настраиваемые навязчивые коллекции (из которых у меня есть значительная библиотека). Я неоднократно предоставлял поставщику в этой области четырехкратную (и более) пропускную способность без увеличения пакетной обработки на конечных точках сокетов.

У меня есть классы OrderBook и OrderBook :: Universe, которые занимают менее 2 uss для новой, вставки, поиска, частичной заливки, поиска, второй заливки, стирания, удаления последовательности, когда усреднено более 22000 инструментов. Бенчмарк перебирает все 22000 инструментов последовательно между первым заполнением вставки и последним заполнением, поэтому не нужно использовать дешевые приемы кэширования. Операции в одной и той же книге разделены доступом 22000 разных книг. Это очень НЕ кеширующие характеристики реальных данных. Реальные данные гораздо более локализованы во времени, и последовательные сделки часто попадают в одну книгу.

Вся эта работа включает в себя тщательное рассмотрение констант и характеристик кэширования в любой из алгоритмических затрат используемых коллекций. (Иногда кажется, что K в K O (n) K O (n * log n) и т. Д. И т. Д. И т. Д. Отбрасываются слишком легко)

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

Кто-нибудь на самом деле получает 2000000 + / м / с производительности из управляемой среды?Я знаю нескольких людей на этой арене, и никто никогда не хвастался этим.И я думаю, что 2 мм в управляемой среде имели бы некоторые права бахвальства.

Я знаю, что декодер порядка FIX одного крупного игрока выполняет 12000000 полевых декодирований / сек.(3Ghz CPU) Это C ++, и тот, кто написал это, почти бросил вызов любому, кто придумал что-то в управляемой среде, даже вдвое меньше скорости.

С технической точки зрения это интересная область с множеством забавных проблем с производительностью,Рассмотрим рынок опционов при изменении базовой ценной бумаги - скажем, 6 невыполненных ценовых пунктов с 3 или 4 различными датами истечения срока действия.Теперь для каждой сделки было, вероятно, 10-20 котировок.Эти котировки могут вызвать изменения цен в опционах.Таким образом, для каждой сделки может быть 100 или 200 изменений в котировках опционов.Это всего лишь тонна данных, а не объем данных, подобный детектору столкновений с Большим адронным коллайдером, но все же представляет собой небольшую проблему.Это немного отличается от нажатия клавиш.

Даже дебаты о FPGA продолжаются.Многие люди считают, что хорошо закодированный парсер, работающий на 3GHZ, может превзойти 500 МГц FPGA.Но даже если чуть-чуть медленнее (не говоря о том, что они есть), системы на основе FPGA могут иметь тенденцию к более жесткому распределению задержек.(Прочитайте «тенденцию» - это не общее утверждение) Конечно, если у вас есть отличный синтаксический анализатор C ++, который вы проталкиваете через Cfront, а затем проталкиваете его через генератор изображений FPGA ... Но это еще один спор ...

27 голосов
/ 04 июля 2010

Многое сводится к простой разнице между фактом и теорией. Люди выдвинули теории , чтобы объяснить, почему Java должна (или, по крайней мере, может быть) быстрее, чем C ++. Большинство аргументов имеют мало общего с Java или C ++ как таковыми , но с динамической и статической компиляцией, при этом Java и C ++ на самом деле являются немногим больше, чем примеры двух (хотя, конечно, возможно компилировать Java статически или C ++ динамически). У большинства из этих людей есть эталоны, чтобы «доказать» свои претензии. Когда эти контрольные показатели рассматриваются в любой детали, быстро становится очевидным, что во многих случаях они предпринимали довольно экстремальные меры для получения желаемых результатов (например, целое число enable оптимизация при компиляции Java, но конкретно отключена оптимизация при компиляции C ++).

Сравните это с Играми по тестированию компьютерного языка , где почти каждый может подать заявку, поэтому весь код имеет тенденцию быть оптимизированным в разумной степени (а в некоторых случаях даже необоснованная степень). Кажется довольно ясным, что значительное число людей воспринимает это как соревнование, когда сторонники каждого языка делают все возможное, чтобы «доказать», что их предпочтительный язык - лучший. Поскольку любой может представить реализацию любой проблемы, особенно плохое представление мало влияет на общие результаты. В этой ситуации C и C ++ становятся явными лидерами.

Хуже того, эти результаты, вероятно, показывают, что Java в лучше в свете, чем полностью точна. В частности, тот, кто использует C или C ++ и действительно заботится о производительности, может (и часто будет) использовать компилятор Intel вместо g ++. Это обычно даст по крайней мере 20% -ное улучшение скорости по сравнению с g ++.

Редактировать (в ответ на пару замечаний, поднятых Джальфом, но слишком длинных, чтобы уместно вписаться в комментарии):

  1. указатели, являющиеся кошмаром писателей-оптимизаторов. Это действительно преувеличивает вещи (совсем) немного. Указатели приводят к возможности создания псевдонимов, что предотвращает определенные оптимизации при определенных обстоятельствах. Тем не менее, встраивание предотвращает вредные эффекты большую часть времени (то есть компилятор может определить, есть ли псевдоним, а не всегда генерировать код в предположении, что он может быть). Даже если в коде необходимо использовать псевдонимы, кэширование сводит к минимуму снижение производительности при этом (т. Е. Данные в кеше L1 только на минут медленнее, чем данные в регистре). Предотвращение алиасов может повысить производительность в C ++, но не так сильно, как вы думаете.

  2. Распределение мусора происходит намного быстрее. Несомненно, что во многих реализациях C ++ распределитель по умолчанию работает медленнее, чем то, что обеспечивает большинство (текущих) распределителей сборки мусора. Это уравновешено (по крайней мере до некоторой степени) тем фактом, что выделения в C ++, как правило, находятся в стеке, что также быстро, тогда как в языке GC почти все выделения обычно находятся в куче. Хуже того, в управляемом языке вы обычно выделяете пространство для каждого объекта индивидуально, тогда как в C ++ вы обычно выделяете пространство для всех объектов в области видимости вместе.

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

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

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

14 голосов
/ 04 июля 2010

JIT-компилятор теоретически может выполнить много оптимизаций, да, но как долго вы готовы ждать?Приложению C ++ может потребоваться несколько часов для компиляции, потому что это происходит в автономном режиме, и пользователь не сидит, постукивая пальцами и ожидая.

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

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

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

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

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

С другой стороны, в C # нет указателей, которые являются кошмаром оптимизирующего компилятора.А выделение памяти в управляемом языке намного дешевле, чем в C ++.

В любом случае есть свои преимущества, поэтому наивно ожидать, что вы можете получить простой ответ «один или другой».В зависимости от точного исходного кода, компилятора, ОС, аппаратного обеспечения, на котором он запущен, один или другой могут работать быстрее.И в зависимости от ваших потребностей, сырая производительность не может быть целью № 1.Возможно, вы больше заинтересованы в быстроте реагирования, во избежании непредсказуемых остановок.

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

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

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

9 голосов
/ 04 июля 2010

Эти фирмы, как правило, не имеют ограничений относительно того, насколько дорогое оборудование.

Если им также все равно, насколько дорого обходится программное обеспечение, то я думаю, что, конечно, C ++ может быть быстрее: например, программист может использовать выделенную или предварительно выделенную память; и / или они могут выполнять код в ядре (избегая кольцевых переходов) или в режиме реального времени, и / или иметь его в тесной связи со стеком сетевых протоколов.

2 голосов
/ 06 июля 2010

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

Я думаю, что эта среда меняет аргумент.Например, если разница между скоростью выполнения c ++ и c # составляет 25%, то в игру вступают другие факторы.Когда это выполняется в сетке, может не иметь значения, как он закодирован, так как весь процесс после распределения по машинам может не быть проблемой или решаться путем выделения или покупки еще нескольких машин.Самым важным вопросом и стоимость может стать «время выхода на рынок», где c # может оказаться победителем и более быстрым вариантом.

Что быстрее c ++ или c #?

C # byшесть месяцев ......

2 голосов
/ 04 июля 2010

Это может быть не по теме, но пару недель назад я смотрел видео, которое может вас заинтересовать: http://ocaml.janestreet.com/?q=node/61

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

2 голосов
/ 04 июля 2010

Простой факт заключается в том, что C ++ предназначен для скорости. C # / Java нет.

Возьмем неисчислимые иерархии наследования, характерные для этих языков (например, IEnumerable), по сравнению с нулевыми накладными расходами в std :: sort или std :: for_each, которые являются универсальными. Необработанная скорость выполнения C ++ необязательно немного выше, но программист может проектировать быстрые системы или системы с нулевыми издержками. Даже такие вещи, как переполнение буфера - вы не можете отключить их обнаружение. В C ++ у вас есть контроль. По сути, C ++ - это быстрый язык - вы не платите за то, что не используете. Напротив, в C #, если вы используете, скажем, stackalloc, вы не можете НЕ выполнять проверку переполнения буфера. Вы не можете размещать классы в стеке или непрерывно.

Существует также целый момент времени компиляции, когда приложения на C ++ могут занимать гораздо больше времени, как для компиляции, так и для разработки.

2 голосов
/ 04 июля 2010

Есть причины использовать C ++, кроме производительности. Существует ОГРОМНАЯ библиотека библиотек C и C ++. Переписать все это на альтернативных языках было бы нецелесообразно. Для того, чтобы такие вещи, как P / Invoke, работали правильно, целевой код должен быть спроектирован так, чтобы его вызывали из других источников. В противном случае вам придется написать какую-то оболочку для вещей, представляющих полностью C API, потому что вы не можете P / Invoke для классов C ++.

Наконец, P / Invoke - очень дорогая операция.

JIT-компиляторы становятся все лучше и лучше. Они могут выполнять оптимизацию во время работы программы

Да, они могут это сделать. Но вы забываете, что любой компилятор C ++ способен выполнять те же оптимизации. Конечно, время компиляции будет хуже, но сам факт того, что такая оптимизация должна выполняться во время выполнения, является чрезмерным. Существуют случаи, когда управляемые языки могут опередить C ++ в определенных задачах, но обычно это происходит из-за их моделей памяти, а не из-за оптимизации времени выполнения. Строго говоря, у вас, конечно, может быть такая модель памяти в C ++, EDIT: такая, как обработка строк в C #, / EDIT, но лишь немногие программисты на C ++ тратят столько же времени на оптимизацию своего кода, как ребята из JIT.

Есть некоторые проблемы с производительностью, которые являются наследственным недостатком для управляемых языков, а именно дисковый ввод-вывод. Это единовременная стоимость, но в зависимости от приложения она может быть значительной. Даже с лучшими оптимизаторами вам все равно нужно загрузить 30 МБ + JIT-компилятора с диска при запуске программы; тогда как бинарный файл C ++ редко достигает такого размера.

1 голос
/ 06 июля 2010

Одна из самых интересных вещей в C ++ состоит в том, что его показатели производительности не лучше, а более надежны 1002 *.

Это не обязательно быстрее, чем Java / C # / ..., но это согласованно во всех запусках .

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

1 голос
/ 04 июля 2010

В HFT задержка является большей проблемой, чем пропускная способность.Принимая во внимание параллелизм источника данных, вы всегда можете добавить больше ядер к проблеме, но вы не можете компенсировать время отклика с большим количеством оборудования.Независимо от того, был ли язык скомпилирован заранее, или Just-In-Time, сборка мусора может разрушить вашу задержку.Существуют виртуальные машины реального времени с гарантированной задержкой сборки мусора.Это довольно новая технология, боль в настройке и смехотворно дорогая, но если у вас есть ресурсы, это можно сделать.Вероятно, в ближайшие годы она станет гораздо более популярной, так как первые пользователи финансируют НИОКР, которые сейчас ведутся.

...