Selain jawaban penyetelan perangkat keras / pengaturan yang sangat baik dari @jimwise, "linux latensi rendah" menyiratkan:
- C ++ untuk alasan determinisme (tidak ada penundaan kejutan saat GC masuk), akses ke fasilitas tingkat rendah (I / O, sinyal), kekuatan bahasa (penggunaan penuh TMP dan STL, keamanan jenis).
- lebih suka kecepatan-over-memori:> 512 Gb RAM adalah umum; basis data ada dalam memori, cache di muka, atau produk NoSQL yang eksotis.
- pilihan algoritma: as-fast-as-possible versus waras / dapat dimengerti / extensible, mis. bebas-bit, beberapa array bit alih-alih array-of-object-with-bool-properties.
- penggunaan penuh fasilitas OS seperti Memori Bersama antar proses pada inti yang berbeda.
- aman. Perangkat lunak HFT biasanya ditempatkan bersama di Bursa Efek sehingga kemungkinan malware tidak dapat diterima.
Banyak dari teknik ini tumpang tindih dengan pengembangan game yang merupakan salah satu alasan mengapa industri perangkat lunak keuangan menyerap programer game yang baru-baru ini berlebihan (setidaknya sampai mereka membayar tunggakan uang sewa).
Kebutuhan mendasar adalah untuk dapat mendengarkan aliran data pasar bandwidth yang sangat tinggi seperti harga sekuritas (saham, komoditas, fx) dan kemudian membuat keputusan beli / jual / lakukan-tidak cepat berdasarkan keamanan, harga dan kepemilikan saat ini.
Tentu saja, ini semua bisa salah secara spektakuler .
Jadi saya akan menguraikan titik array bit . Katakanlah kita memiliki sistem Perdagangan Frekuensi Tinggi yang beroperasi pada daftar Pesanan yang panjang (Beli 5k IBM, Jual 10k DELL, dll). Katakanlah kita perlu menentukan dengan cepat apakah semua pesanan dipenuhi, sehingga kita dapat beralih ke tugas berikutnya. Dalam pemrograman OO tradisional, ini akan terlihat seperti:
class Order {
bool _isFilled;
...
public:
inline bool isFilled() const { return _isFilled; }
};
std::vector<Order> orders;
bool needToFillMore = std::any_of(orders.begin(), orders.end(),
[](const Order & o) { return !o.isFilled(); } );
kompleksitas algoritmik dari kode ini menjadi O (N) karena merupakan pemindaian linier. Mari kita lihat profil kinerja dalam hal akses memori: setiap iterasi dari loop di dalam std :: any_of () akan memanggil o.isFilled (), yang diuraikan, sehingga menjadi akses memori _isFilled, 1 byte (atau 4 tergantung pada arsitektur Anda, penyusun dan pengaturan penyusun) dalam objek katakanlah total 128 byte. Jadi kita mengakses 1 byte di setiap 128 byte. Ketika kita membaca 1 byte, dengan anggapan kasus terburuk, kita akan kehilangan cache data CPU. Ini akan menyebabkan permintaan baca ke RAM yang membaca seluruh baris dari RAM ( lihat di sini untuk info lebih lanjut ) hanya untuk membaca 8 bit. Jadi profil akses memori sebanding dengan N.
Bandingkan ini dengan:
const size_t ELEMS = MAX_ORDERS / sizeof (int);
unsigned int ordersFilled[ELEMS];
bool needToFillMore = std::any_of(ordersFilled, &ordersFilled[ELEMS+1],
[](int packedFilledOrders) { return !(packedOrders == 0xFFFFFFFF); }
profil akses memori dari ini, dengan asumsi kasus terburuk lagi, adalah ELEMS dibagi dengan lebar garis RAM (bervariasi - bisa dual-channel atau triple-channel, dll).
Jadi, sebenarnya, kami mengoptimalkan algoritme untuk pola akses memori. Tidak ada jumlah RAM yang akan membantu - ini adalah ukuran cache data CPU yang menyebabkan kebutuhan ini.
Apakah ini membantu?
Ada CPPCon yang sangat baik berbicara tentang pemrograman latensi rendah (untuk HFT) di YouTube: https://www.youtube.com/watch?v=NH1Tta7purM