35 puan yazan GN⁺ 2024-03-04 | 6 yorum | WhatsApp'ta paylaş
  • 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

 
cosine20 2024-03-07
  1. adımda somut olarak hangi işlemlerin yapıldığını merak ediyorum. Performans artışının inanılmaz derecede yüksek olduğu bölüm orası lol
 
sddsdd94 2024-03-06

Her adımı ayrı ayrı ayırıp performans iyileşme süresini göstermesi ilginç olmuş :)

 
galadbran 2024-03-05

wc ile de 1 dakikada olur.... demek ki en iyisi yine kod yazmamakmış... haha

 
jhbaek 2024-03-05

Gü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)

 
misolab 2024-03-05

Organizasyona göre optimize edilmiş kod!!

 
GN⁺ 2024-03-04
Hacker News görüşleri
  • İlk kullanıcı, veri işleme için kod optimizasyonu deneyimi olmadığı için cat, wc vb. 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.
  • İkinci kullanıcı, Polars kütüphanesi kullanıldığında işlem süresinin 33 saniye olduğunu belirterek, en hızlı elle optimize edilmiş çözüme yaklaşan en basit çözüme duyduğu ilgiyi ifade ediyor.
  • Üçüncü kullanıcı, Go dilinin performans analiz raporlarının kafa karıştırıcı olduğunu söylüyor; belirli bir kod satırının çalışma süresi sezgisel görünmüyorsa, bunun verinin öngörülmesinin zor olmasından ve dallanma tahminleyicisinin yanlış tahmin yapabilmesinden kaynaklanabileceğini açıklıyor.
  • Dördüncü kullanıcı, Go diliyle 1BRC'yi (1 Billion Row Challenge) yapma sonucunu paylaşarak Go’ya özgü optimizasyon teknikleri öğrendiğini belirtiyor. Örneğin unsafe.Pointer kullanarak sınır denetimi olmadan bellek okuma, standart kütüphanedeki bytes ve bits paketlerinin bazı işlevlerinin assembly ile yazılmış olması, garbage collection’ı kapatma ayarı ve goroutine’leri thread’lere sabitleme gibi yöntemler.
  • Beşinci kullanıcı, shell script geliştiricisinin, diğer dil geliştiricileri hazırlanırken belirli 1 milyar satırlık veriyi çoktan işlemiş olacağını iddia ediyor.
  • Altıncı kullanıcı, veritabanlarının uygulama kodundan daha hızlı, daha az karmaşık ve veri güncellemelerine karşı daha dayanıklı olduğunu savunuyor; bu yüzden daha fazla işin veritabanında yapılması gerektiğini vurguluyor.
  • Yedinci kullanıcı, 2010 yılında PostgreSQL kullanarak Environment Canada’nın 270 milyon satırlık iklim verisini sorgulayan bir web uygulaması geliştirdiğini ve bu yazılımın ödül aldığını paylaşıyor. Uygulama, raporları 1 dakikadan kısa sürede üretecek şekilde optimize edilmiş.
  • Sekizinci kullanıcı, Go dilinde paralel kodun hâlâ Go’nun deyimsel kod stilini korumasının hoş olduğunu belirtiyor.
  • Dokuzuncu kullanıcı, CLI’de büyük metin dosyalarıyla çalışırken Unicode ayrıştırmasını atlamanın awk, grep vb. araçları belirgin biçimde hızlandırdığını söylüyor; awk çözümüne LC_ALL=C eklenirse işlem süresinin 1 dakikanın altına indirilebileceğini iddia ediyor.
  • Son kullanıcı, en hızlı Java sürümünün en hızlı Go sürümünden daha hızlı olmasının ilginç olduğunu belirtiyor ve Java Virtual Machine’in (JVM) performansını oldukça iyi buluyor.