- 1BRC: 1 milyar satırlık bir metin dosyasındaki sıcaklık ölçümlerini okuyup istasyon bazında minimum/ortalama/maksimum sıcaklığı hesaplayan kod yazma meydan okuması
- 1 Ocak 2024 ile 31 Ocak 2024 arasında gerçekleştirildi ve amaç, en güncel Java’yı mümkün olduğunca yoğun kullanmaktı
- Bunun üzerine insanlar ilgi gösterip farklı dillerle (Rust, Go, C++, SQL) denemeler yapmaya başladı
- Go ile yazılmış 9 çözüm ayrıntılı olarak tanıtılıyor (en yavaştan en hızlıya doğru)
Temel ölçümler
cat komutuyla 1 milyar satırlık metin verisini (13GB) okuma süresi 1.052 saniye.
- Dosyayı gerçekten işleyen
wc komutu ise neredeyse 1 dakika sürüyor (55.710 saniye).
- Sorunu AWK çözümüyle çözmek 7 dakika 35 saniye sürüyor.
Çözüm 1: Basit ve idiomatik Go
- Go standart kütüphanesini kullanan ilk çözüm 1 dakika 45 saniye sürüyor.
- Satırlar
bufio.Scanner ile okunuyor, strings.Cut ile ';' karakterine göre ayrılıyor.
- Sıcaklık
strconv.ParseFloat ile parse ediliyor ve sonuçlar Go map’i kullanılarak biriktiriliyor.
Çözüm 2: Pointer değerli map
- Map içinde iki kez hashing yapmaktan kaçınmak için
map[string]*stats kullanılıyor.
- Pointer değerleri kullanılarak süre 1 dakika 45 saniyeden 1 dakika 31 saniyeye indiriliyor.
Çözüm 3: strconv.ParseFloat kullanmamak
- Sıcaklığı parse etmek için
strconv.ParseFloat yerine özel yazılmış kod kullanılıyor.
- Süre 1 dakika 31 saniyeden 55.8 saniyeye düşüyor.
Çözüm 4: Sabit noktalı tamsayı kullanmak
- Kayan nokta işlemlerinden kaçınmak için sıcaklık tamsayı olarak temsil ediliyor.
- Süre 55.8 saniyeden 51.0 saniyeye düşüyor.
Çözüm 5: bytes.Cut kullanmamak
- ';' karakterini bulmak için tüm istasyon adını taramak yerine sondan başlayarak parse ediliyor.
- Süre 51.0 saniyeden 46.0 saniyeye düşüyor.
Çözüm 6: bufio.Scanner kullanmamak
bufio.Scanner kaldırılıp dosya büyük parçalar halinde okunuyor.
- Süre 46.0 saniyeden 41.3 saniyeye düşüyor.
Çözüm 7: Özel hash tablosu
- Go’nun map’i yerine özel bir hash tablosu uygulanıyor.
- Süre 41.3 saniyeden 25.8 saniyeye düşüyor.
Çözüm 8: Chunk’ları paralel işleme
- Basit ve idiomatik kod paralelleştirilerek süre 1 dakika 45 saniyeden 24.3 saniyeye indiriliyor.
Çözüm 9: Tüm optimizasyonlar ve paralel işleme
- Tüm optimizasyonlar paralel işlemeyle birleştirilerek süre 24.3 saniyeden 3.99 saniyeye indiriliyor.
Sonuç tablosu
- Tüm Go çözümlerini ve en hızlı Go ile Java çözümlerini karşılaştıran bir tablo sunuluyor.
- Go sürümleri içinde en hızlı olanı 2.90 saniyede, Java sürümü ise 0.953 saniyede işliyor.
- 1 saniyenin altına inen Java sürümü Thomas Wuerthinger’in (GraalVM’in yaratıcısı) çalışması; muhtemelen bu alandaki uzmanlığı sayesinde mümkün olmuş.
Son yorumlar
- Günlük programlama işlerinde basit ve idiomatik kod iyi bir başlangıç noktasıdır.
- Veri işleme hattı kurarken kodu 4 kat veya 26 kat hızlandırmak, kullanıcı memnuniyetini artırıp hesaplama maliyetlerini düşürebilir.
- Runtime veya interpreter geliştiriyorsanız performans artışı önemlidir.
GN⁺ görüşü
- Bu yazı, Go diliyle büyük ölçekli veri işlemeyi optimize etmenin farklı yollarını inceleyerek performans optimizasyonuna dair ilgi çekici bir vaka çalışması sunuyor.
- Optimizasyon sürecinde Go’nun standart kütüphanesinin ötesine geçip özel hash tablosu gibi veri yapıları uygulamanın önemli rol oynadığını gösteriyor.
- Paralel işlemenin etkisini vurguluyor ve tek çekirdek optimizasyonuyla paralelleştirmeyi birleştirerek çarpıcı performans artışı sağlıyor.
- Performansa duyarlı uygulamalar geliştiren yazılım mühendisleri için faydalı içgörüler sunuyor.
- Bu optimizasyonların gerçek üretim ortamında ne kadar yararlı olacağı kullanım senaryosuna bağlı olabilir. Her uygulama bu düzeyde optimizasyon gerektirmeyebilir.
6 yorum
Her adımı ayrı ayrı ayırıp performans iyileşme süresini göstermesi ilginç olmuş :)
wcile de 1 dakikada olur.... demek ki en iyisi yine kod yazmamakmış... hahaGüzel yazıyı paylaştığınız için teşekkürler. Bir zamanlar sistem optimizasyonuna kafayı taktığım dönem aklıma geldi haha.
Geliştirici olarak deneyimim arttıkça, en üst düzeyde optimize edilmiş kodun bakımının zor olduğunu ve ekip ortamında işletmesinin güçleştiğini birçok kez deneyimledim; bu yüzden zamanla optimizasyon yolundan uzaklaştım. (bir anda kişisel bir geri bakış oldu)
Organizasyona göre optimize edilmiş kod!!
Hacker News görüşleri
cat,wcvb. kullanarak temel ölçüm değerleri elde edilen ilk bölümün özellikle ilgi çekici olduğunu belirtiyor. Bunun, “makul” bir aralık elde etmenin kolay bir yolu olduğunu düşünüyor.unsafe.Pointerkullanarak sınır denetimi olmadan bellek okuma, standart kütüphanedekibytesvebitspaketlerinin bazı işlevlerinin assembly ile yazılmış olması, garbage collection’ı kapatma ayarı ve goroutine’leri thread’lere sabitleme gibi yöntemler.awk,grepvb. araçları belirgin biçimde hızlandırdığını söylüyor;awkçözümüneLC_ALL=Ceklenirse işlem süresinin 1 dakikanın altına indirilebileceğini iddia ediyor.