MercanSoftYazılım Teknolojileri Günlüğü
01 Tem 2019

WebAssembly : Web hiç bu kadar hızlı olmamıştı

WebAssembly : Web hiç bu kadar hızlı olmamıştı

Yazılım geliştirmeye başladığım ilk yıllarda, daha ortada Mobile Developer diye bir kavram yokken, genelde bize sunulan iki tane yol haritası vardı. Ya web uygulamaları ya da desktop uygulamaları geliştirmekte uzmanlaşacaktık. Bu gerçekten o zamanlar bir seçimdi, her platformun (Web, Desktop) kendine özgü dinamikleri vardı, avantajları, dezavantajları vardı. “Desktop uygulamaları her zaman daha hızlıdır!”, “Web uygulamalarını daha çok kişiye daha kolay ulaştırırsın!” gibi argümanlar çarpışıyordu. Bir de Game Developer’lar vardı ki kendilerine hep özenirdim. Sanırım her developer hayatının bir döneminde oyun geliştirmek istemiştir. Genelde performansla ilgili tartışmalara son noktayı koyan şu cümle oluyordu “Eğer hız istiyorsan C/C++ ile geliştireceksin, neden bütün oyunlar öyle geliştiriliyor sanıyorsun?”.

Bugün “Web mi? Desktop mı?” diye bir tartışma yok. Web-Desktop savaşını (eğer öyle bir savaş vardıysa) web kazandı. Sanırım bunun en önemli sebepleri; güncelleme kolaylığı, daha fazla insana ulaşabilme, kullanıcılara uygulama yükletmeme gibi avantajların performanstan daha öncelikli olması. Office, Photoshop benzeri uygulamaları artık Browser’lar üzerinden kullandığımız günlerdeyiz.

Benim için web dünyasındaki en önemli mihenk taşlarından biri Google IO 2010’da Html5 ve Css3’ün duyurulmusaydı. O günden beri de client-side’da yapabildiğimiz işleri sayısı giderek artıyor. Javascript bugün tartışmasız bir şekilde dünyadaki en önemli dil.

Bugün web için bir diğer önemli mihenk taşı olan WebAssembly bahsetmek istiyorum.

WebAssembly

WebAssembly nedirden önce ne değildirle başlamak istiyorum ;

  • Bundan sonra Javascript yazmayacağız!!!

Kesinlikle böyle birşey yok arkadaşlar, javascript yazmaya devam edeceğiz. Sadece artık javascript tarafında kullanabileceğimiz, daha önce olmadığı kadar performanslı modüller de yazma imkanımız var.

WebAssembly veya wasm; Browser’lar için geliştirilmiş low-level bir bytecode formatı. C/C++ve Rust gibi low-level dillerde yazdığımız kodların derlenip browser’da çalışmasına olanak sağlıyor ve şu an bütün Browser’lar tarafından destekleniyor.

Proje 2015 yılında Google, Mozilla, Apple ve Microsoft’un bir araya gelerek WebAssembly Community Group’u kurmalarıyla başladı. Şuan belli bir olgunluk seviyesine ulaşmış durumda.

Konunun detaylarına girmeden önce neden WebAssembly gibi bir teknolojiye ihtiyaç duyulduğundan bahsetmek istiyorum.

Javascript Neyinize Yetmiyor!

Javascript 1995 yılında Brendan Eich tarafından on gün içerisinde geliştirildiğinden beri oldukça yol katetti ve bugün sekizinci versiyonu olan ECMAScript 2017 çıkmış durumda.

Javascript çok güzel ve yetenekli bir dynamic-typed dil. Fakat on günde yazılımış bir dile göre şaşırtıcı derecede, fazla sayıda kötü tarafı var 🙂 Bu kötü taraflarından kaçınmak ve performanslı kod yazabilmek için derinlemesine javascript bilmek gerekiyor.

Browser’larda geliştirdiğimiz uygulamalardan beklentiler her geçen gün artıyor ve dolayısıyla javascript’le yazılan uygulamalar giderek büyüyorlar. Uygulama geliştirmeyi kolaylaştırmak, verimliliği arttırmak ve javascript’in bu kötü taraflarından kaçınmak amacıyla yıllar içerisinde javascript’e compile olan (super-set’ler, sub-set’ler) bir sürü yeni dil yazıldı. Bunlara en iyi örnekler DartCoffeeScript ve TypeScript.

Browser üreticileri ise her versiyonda kendi javascript engine’lerini (Google V8, Microsoft Chakra, Mozilla SpiderMonkey) geliştirerek javascript’in daha hızlı, performanslı çalışmasını sağlıyorlar.

Fakat javascript dynamic-typed bir dil ve static-typed dillere karşılaştırılınca optimize edilmesinin bir sınırı var. Özellikle günümüzde 3d, VR (Virtual Reality) gibi işlerin browser’lara taşınmasıyla beraber performans beklentileri iyice yükseldi.

Yani javascript’in bottleneck olduğu bir noktaya doğru gidiyoruz. İşte WebAssembly’e ihtiyaç tam bu noktada çıkıyor. Performans!!!

Bu noktada bir kaç örnekle gitmek istiyorum.

Android dünyasında performans kritik yerlerde NDK (Native Development Kit) kullanılıyor, yani C/C++ kullanarak uygulama geliştirebiliyorsunuz.

Aynı şekilde birçok Image Processing, Video Compression, Machine Learning, Cryptography vb. alt yapılarının C/C++ ile geliştirilmesinin bir sebebi var o da performans.

İşte WebAssembly bütün bu performans kritik işleri Browser’larda yapmamıza imkan sağlıyor. Bu algoritmaları kullanabilmek için artık server’a istek atmadığımız bir dünyayı düşünün 🙂 Bu algoritmaları artık web uygulamamızla beraber paketleyip, browser üzerinde çalıştırabileceğiz.

Ne demek istediğimi bir demo daha iyi anlatır sanırım ;

Buradan WebAssembly ile yapılmış bir video editor’ün ne kadar performanslı olduğuna ve javascript’le karşılaştırmasına bakabilirsiniz.

Yine benim çok hoşuma giden bir proje daha var. Construct bir oyun yapma uygulaması. Çok yakın zamanda editör’lerini WebAssembly ile derleyip bir web uygulaması olarak açmışlar. Buradan deneyebilirsiniz. Editör içerisinde hazırladığınız oyunu başlatma seçeneği de var ve bütün bunlar çok hızlı gerçekleşiyor.

Peki Nasıl Çalışıyor WebAssembly?

C/C++ veya Rust ile yazdığınız kod binary formatta bir AST’ye (Abstract Syntax Tree) derlenir ve browser’a gönderilir. Javascript gibi interpret(yorumlanan) edilen dillerin aksine run-time da herhangi bir parsing işlemi yapılmadığından dolayı başlangıç zamanı çok daha hızlıdır. Çünkü zaten elinizde parsing ve optimizasyon yapılmasına ihtiyaç olmayan bir modül var. Yani AST direkt olarak platforma en uygun en optimize machine koduna derlenebilir.

Ne demek istediğimi anlatmak için Google V8 Engine’in javascript kodunu nasıl machine koda çevirdiğine bakalım. Diğer Browser’lar da benzer şeyler yapıyorlar.

V8 Engine yazdığımız javascript kodunu parse edip AST’ye çeviriyor ve sonrasında da optimize edilmemiş machine koda çeviriyor. Ardından run-time’da V8 engine javascript function’larından fazla CPU tüketen ve optimize edibilecek olanlarını tespit edip TurboFan adını verdikleri bir teknolojiyle analiz edip ortaya optimize olmuş bir machine kod çıkartıyor. Ama bu süreçler elbetteki bedava değil, yine sizin CPU-cycle’larınıza mal oluyor.

Ama wasm zaten static-typed bir dilden üretilmiş bir AST. Gerekli optimizasyonlar zaten compiler tarafından yapılmış durumda. Şemada da göreceğiniz üzere wasm decode ediliyor ve ardından direkt machine koda derleniyor ve bu işlem çok hızlı.

AST ne olduğunun daha iyi anlaşılması için şöyle bir örnek vermek istiyorum.

int factorial(int n)
{
if(n > 1)
return n * factorial(n – 1);
else
return 1;
}

 

Yukarıda gördüğünüz C++ diliyle yazılımış faktoriyel hesaplayan bir function. Yukarıdaki kodu AST’ye çevirdiğimiz zaman ortaya şöyle birşey çıkıyor ;

 

(module
(table 0 anyfunc)
(memory $0 1)
(export “memory” (memory $0))
(export “factorial” (func $factorial))
(func $factorial (param $0 i32) (result i32)
(local $1 i32)
(local $2 i32)
(set_local $2
(i32.const 1)
)
(block $label$0
(br_if $label$0
(i32.lt_s
(get_local $0)
(i32.const 2)
)
)
(set_local $2
(i32.const 1)
)
(loop $label$1
(set_local $2
(i32.mul
(get_local $0)
(get_local $2)
)
)
(set_local $1
(i32.gt_s
(get_local $0)
(i32.const 2)
)
)
(set_local $0
(i32.add
(get_local $0)
(i32.const -1)
)
)
(br_if $label$1
(get_local $1)
)
)
)
(get_local $2)
)
)

 

Bu çıktıya wast ve ya wat deniliyor. Browser’ların compile ettiği ise yukarıdaki çıktının binary hali yani wasm yani WebAssembly 🙂

Artık elimizde wasm var, peki bu aşamadan sonra ne oluyor. Bir wasmmodülünü kullanabilmeniz için javascript’e ihtiyacınız var. Buna Js “glue” code deniyor. Yani wasm ile javascript’i birbirine bağlıyorsunuz. Mesela yukaraki C++ ile yazılmış kodu kullanmak istersek şöyle bir tanım yapmamız gerekiyor.

var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, wasmImports);
log(wasmInstance.exports.factorial(10));

 

 

 

Yukarıdaki koda modülü initialize eden yerleri koymadım ama konsept olarak bu şekilde C++ tarafındaki tanımladığımız metotlara ulaşabiliyoruz. Hatta yazdığınız C++ sınıfları javascript nesnelerine map edilebiliyor.

Bu ilişkinin çift taraflı olduğunu da belirmek istiyorum. Yani javascript tarafından C++ function’larını çağırabileceğiniz gibi tam tersini de yapmanız mümkün. Şuan ki haliye WebAssembly, Browser’ın sağladığı API’lere (Mikrofon, Web Cam vb.) sadece javascript üzerinden erişebiliyor. Sizin de anlayacağınız üzere Javascript’in bir yere gittiği yok 🙂 WebAssembly sadece ona yeni yetenekler kazandırıyor. Patron hala javascript.

Ayrıca yine WebAssembly içerisinden DOM element’lerine direkt erişip, değişiklik yapmanız da mümkün. Yani teorik olarak bütün bir uygulamayı WebAssembly kullanarak da yazabilirsiniz.

WebAssembly ile ilgili bir diğer şey ise, Browser’ın indirdiği modüllerin late-binding’e (linking) izin vermesi. Yani apayrı kişiler tarafından geliştirilmiş modüller birleşerek bir uygulama oluşturabilirler, örneğin birinin yazdığı standart bir modül, başka bir modül içerisine referans verilerek kullanılabilir. Kast ettiğim şey jquery’i google cdn’den sitesinize eklemenizden farklı birşey değil.

C++ kodlarından wasm elde etmek ve test etmek için yeni bir Fiddle sitesi yapmışlar 🙂 WasmFiddle. Bakmanızı tavsiye ederim, WebAssembly’i denemek istiyorsanız sizi baya hızlandırabilir.

Bi asm.js Vardı Ona Ne Oldu?

asm.js aslında WebAssembly’e ilham olan proje. Mozilla tarafından geliştirilmiş bir Javascripty sub-set’i. C ile yazdığınız kodların optimize olmuş javascript’lere compile olmasını sağlıyor. Örn ;

int add(int i) {
  return i + 1;
}

Şeklindeki bir C kodunun çıktısı aşağıdaki gibi oluyor ;

function add(i) {
  i = i|0;
  return (i + 1)|0;
}

 

| ile bitwise or işleminin yapıldığını görebilirsiniz, javascript’de bitwise or işlemi aynı zamanda işleme giren değişkeni integer’a çevirir. Yani hemen altındaki topla işleminde artık i değişkeninin kesin olarak integer olduğu biliniyor. Javascript gibi dynamic-typed bir dilde bunu önceden bilmek önemli bir performans artışı sağlar. Şunu demek istiyorum ;

 

Yukara gördüğünüz Javascript Engine’lerinin + operatörünü gördüklerindeki davranış şekli :D. Dinamik ve type safety olmayan bir dil olduğundan dolayı JS Engine her ihtimali düşünmek zorunda, parametre olarak int değil string de gelmiş olabilir.

asm.js kullanarak üretilen javascript çıktıları parse edilmesi ve machine koduna çevrilmesi işlemi daha optimize yapılıyor. Yani aslında asm.js ile yapılan tam olarak AOT Compilation(ahead-of-time compilation).

Peki neden asm.js gibi native hızlara yakın hızlarda çalışan bir yapı varken WebAssembly’e geçiyoruz?

Bunun birkaç sebebi var. En önemlisi WebAssembly bütün büyük Browser üreticilerinin bir araya gelmesiyle geliştirilen bir proje. Yani standartları oldukça net ve bütün browser’larda aynı şekilde benzer performans’larla çalışıyor.

Ayrıca Binary wasm çıktısının decode edilmesi asm.js çıktısının parse edilmesinden 20 kat daha hızlı şekilde gerçekleşiyor. Bu da uygulamanın başlama hızını oldukça arttırıyor.

asm.js ne kadar optimize kod üretirse üretsin aslında ürettiği javascript ve dolayısıyla javascript’in limitasyonlarında geliştirme yapabiliyoruz. Fakat WebAssembly ile beraber C/C++ gibi native özellikli dillerin avantajlarından yararlanabiliyoruz ve bu da belli noktalarda çok daha performanslı kodlar yazmamıza imkan sağlıyor.

WebAssembly ve Node.js

Yazıyı buraya kadar okuduktan sonra WebAssembly‘in sadece Browser’da çalışan bir teknoloji olduğunu düşünmüş olabilirsiniz. Ama Node.js, Google V8 Engine kullandığından dolayı WebAssembly modüllerini kullanabiliyorsunuz. Hatta bu şekilde geliştirdiğiniz node.js uygulamalarında ürettiğiniz WebAssembly modüllerini hem Browser tarafında hem de back-end de ortaklaştırmanız da mümkün 🙂

WebAssembly ve Diğer Diller

Ağırlıklı olarak C# ile uygulama geliştiren biri olarak ilk işim C# ile WebAssembly geliştirmeyi araştırmak oldu.

Deneysel bir proje olarak Blazor’ı buldum. İncelemenizi tavsiye ederim.

Ama resmi olarak şuan C#, Java gibi managed ve bir VM üzerine çalışan dillere destek yok. Bunun en büyük sebebi de bu tür dillerin kendi run-time’larından Garbage Collector, Thread gibi beklentilerinin olması 🙂

WebAssembly şuanki haliye bir MVP (Minimum Viable Product) ve bu özellikler MVP içerisine alınmamış. Ama resmi sitelerinin dökümantasyon kısmında Post-MVP diye bir bölüm var, şuan geliştirmekte oldukları özellikler arasında GC ve Thread özelliklerinin de olduğunu görebilirsiniz.

Peki WebAssembly Kullanmalı Mıyız?

Hala yeni bir teknoloji ama üzerinde Microsoft, Google, Apple, Mozilla gibi büyük şirketlerin çalıştığını göz önünde bulundurusak ilerleyen yıllarda bir standart olacağını ön görebiliriz. Bence bir Web Developer olarak üzerinde denemeler yapmaya başlamanız lazım. Eğer hem JavaScript hem de C/C++ bilen biriyseniz zaten öğrenmeniz çok uzun sürmeyecektir.

Bir sonraki yazımda görüşünceye dek hepinize iyilikler dilerim.

Programlama Leave a comment

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir