2 puan yazan GN⁺ 2025-07-14 | 1 yorum | WhatsApp'ta paylaş
  • Zig’in yeni asenkron I/O arayüzünün sunulmasıyla, I/O uygulama yönteminin çağıran tarafından doğrudan seçilip enjekte edilmesi mümkün hale geliyor
  • Yeni tasarlanan Io arayüzü, aynı anda hem asenkronluğu hem paralelliği destekliyor ve kod yeniden kullanılabilirliği ile optimizasyona odaklanıyor
  • Blocking I/O, event loop, thread pool, green thread, stackless coroutine gibi çeşitli standart kütüphane uygulamalarının sunulması planlanıyor
  • Yeni API ile future iptali ve kaynak yönetimi, buffering ve daha ayrıntılı giriş/çıkış davranışları mümkün oluyor
  • Mevcut function coloring sorununu çözerek, tek bir kütüphaneyle hem senkron hem asenkron çalışma optimize edilebilir hale geliyor

Genel Bakış

Zig, yakın zamanda yeni bir asenkron I/O arayüzü tasarlayarak, I/O işlemlerinde esneklik ve paralellik desteğine odaklanan bir yöne evriliyor. Bu değişiklik, mevcut async/await paradigmasını ayırarak, gerçek program yazarlarının çok daha çeşitli I/O stratejilerini benimseyebilmesine olanak tanıyacak şekilde tasarlandı.

Yeni I/O Arayüzü

Önceden I/O ile ilgili nesneler doğrudan kod içinde oluşturulup kullanılıyordu; artık ise Io arayüzü çağıran tarafından enjekte ediliyor.

  • Bu yöntem, Allocator desenine benzer şekilde, çağıran tarafın somut I/O uygulamasını seçip enjekte etmesini sağlıyor
  • Harici paket kodlarında da I/O stratejisi tutarlı bir şekilde uygulanabiliyor

Başlıca değişiklikler

  • Io arayüzü artık eşzamanlılık (concurrency) işlemlerini de üstleniyor
  • Kod eşzamanlılığı doğru ifade ettiğinde, Io uygulamasına bağlı olarak paralellik (parallelism) sağlanabiliyor

Örnek kod

  • Eşzamanlılığı olmayan (seri) kod ile io.async ve await üzerinden paralellik olasılığını ifade eden kod karşılaştırılıyor
    • Seri kod: iki dosyaya sırayla kaydeder, paralellik fırsatını kullanamaz
    • Paralel kod: future’lardan yararlanarak dosya kaydeder, asenkron event loop üzerinde daha verimli çalışır

await ve try birleşimi

  • await ile try birlikte kullanıldığında, bir future’da hata oluşursa diğer future’ın kaynaklarını iade edememe sorunu vardır
  • defer ve future.cancel ile uygun iptal ve temizleme açık biçimde yapılabilir

Future.cancel API’si

  • Future.cancel() ve Future.await() idempotenttir (birden çok kez çağrılsa da yan etki oluşturmaz)
  • Tamamlanmış bir future üzerinde cancel çağrılırsa yalnızca kaynaklar serbest bırakılır; tamamlanmamış işler error.Canceled döndürür

Standart Kütüphane I/O Uygulamaları

Io arayüzü, çalışma zamanında çok biçimliliğe dayalı bir arayüzdür; doğrudan uygulanabilir veya üçüncü taraf paketlerin uygulamaları kullanılabilir. Zig’in standart kütüphanesi, çeşitli I/O uygulama türleri sunmayı planlıyor.

  • Blocking I/O: Mevcut C tarzı blocking giriş/çıkışın doğrudan kullanılması, ek yük yok
  • Thread pool: Blocking I/O işlemlerinin OS thread pool’una dağıtılması, bir miktar paralellik sağlar. Ağ istemcileri gibi alanlarda optimizasyon gerekebilir
  • Green thread: Linux’un io_uring gibi asenkron sistem çağrılarından yararlanarak, bir OS thread üzerinde birden çok green (hafif) thread’i işler. Platform desteği gerekir (x86_64 Linux öncelikli)
  • Stackless coroutine: Açık bir stack gerektirmeyen, durum makinesi tabanlı coroutine’ler. WASM gibi bazı platformlarla uyumluluk amacı taşır. Zig derleyicisinde ilgili convention’ın yeniden eklenmesi gerekir

Tasarım Hedefleri

Kod Yeniden Kullanılabilirliği

Asenkron I/O’daki en büyük sorun kodun yeniden kullanılabilirliğidir; diğer dillerde blocking/async fonksiyonlar ayrı bulunduğundan kodun bölünmesi gibi bir problem vardır. Zig’in yaklaşımı ise şunları sağlar:

  • Tek bir kütüphane hem senkron hem asenkron modu etkili biçimde destekleyebilir
  • async/await, “function coloring” olgusunu ortadan kaldırır ve Io sistemi sayesinde çalışma zamanında da çeşitli yürütme modellerine bağımlı kalmaz

Sonuç olarak function coloring sorunu tamamen çözülüyor

Optimizasyon

  • Yeni Io arayüzü, generic olmayan ve vtable tabanlı sanal çağrı yöntemiyle uygulanıyor
  • Sanal çağrılar kod şişmesini azaltır, ancak çalışma sırasında az miktarda ek yük oluşturur. Optimize derlemelerde tek bir Io uygulaması varsa de-virtualization (sanal çağrının kaldırılması) mümkündür
  • Birden fazla Io uygulaması kullanıldığında sanal çağrı korunur (kod tekrarını önlemek amacıyla)

Buffering stratejisi

  • Önceden buffering her uygulama (reader/writer) tarafından üstleniliyordu; artık buffering, Reader ve Writer arayüzü seviyesinde yapılıyor
  • Buffer flush dışında sanal çağrı yoluna girilmediği için optimizasyon kolaylaşıyor

Semantik I/O İşlemleri

Writer arayüzü, belirli optimizasyon işlemleri için iki yeni primitive sunuyor

  • sendFile: POSIX sendfile’dan ilham alır; dosya tanımlayıcıları arasında veri aktarımını çekirdek içinde gerçekleştirir. Bellek kopyalamayı en aza indirir
  • drain: Vectorized write + splatting desteği sağlar. Birden fazla veri segmentini topluca gönderir ve writev sistem çağrısına dönüştürülebilir. splat parametresiyle son öğenin tekrar tekrar kullanılması mümkündür (sıkıştırma gibi akışlarda kullanılabilir)

Yol Haritası

Bu değişikliğin bir bölümü Zig 0.15.0’dan itibaren sunulacak, ancak kütüphanede büyük ölçekli yeniden düzenleme gerektiği için tam geçişin bir sonraki sürümü beklemesi gerekiyor. SSL/TLS, HTTP server/client gibi başlıca modüllerin de yeni Io sistemiyle yeniden tasarlanması planlanıyor

SSS

S: Zig düşük seviyeli bir dilken neden async önemli?

  • Zig, sağlamlık, optimizasyon ve yeniden kullanılabilirlik hedefler
  • Non-blocking giriş/çıkışı standartlaştırarak, diğer kütüphanelerin ve üçüncü taraf kodların da genel I/O stratejisine uyum sağlaması ve yeniden kullanılabilirliğin korunması amaçlanır

S: Paket yazarlarının artık tüm kodlarında async kullanması mı gerekiyor?

  • Hayır. Tüm kodun eşzamanlılığı ifade etmesi gerekmez
  • Genel amaçlı sıralı kod da kullanıcının seçtiği I/O stratejisine uygun şekilde çalışır

S: Hangi yürütme modeli olursa olsun, sadece eklenti takınca her şey mutlaka düzgün çalışır mı?

  • Çoğunlukla evet
  • Ancak koddaki programlama hataları (ör. eşzamanlı iş gereksinimlerinin karşılanmaması) varsa düzgün çalışmaz

Çalışma örnekleriyle birlikte, asenkronluk ve paralellik arasındaki fark ile doğru çalışma akışını tasarlama gerekliliğine de değiniliyor

Sonuç

Zig, yeni Io arayüzünü tanıtarak giriş/çıkış stratejisi seçiminde esnekliği, kodun yeniden kullanılabilirliğini ve optimizasyon imkânını büyük ölçüde artırıyor. Böylece geliştiriciler, asenkron/senkron temelli fonksiyon yazım kısıtları olmadan eşzamanlılık ve paralellik yapısını daha açık ifade edebilir, ayrıca farklı platformlar ve yürütme modellerine de etkili biçimde uyum sağlayabilir.

1 yorum

 
GN⁺ 2025-07-14
Hacker News görüşleri
  • Bu noktayı yeniden vurgulamak istiyorum. Yazıda Zig'in function coloring sorununu tamamen çözdüğü bile söyleniyor ama ben buna katılmıyorum. Meşhur "What color is your function?" yazısındaki 5 kuralı yeniden düşünürsek, Zig'de async/sync/red/blue gibi renkler ayrılmasa da sonuçta yine yalnızca iki durum var: IO fonksiyonları ve IO olmayan fonksiyonlar. Fonksiyon çağırma biçiminin renge göre değişmesi sorununu teknik olarak çözmüş olabilirler, ama hâlâ IO gereken fonksiyonlara IO'yu argüman olarak vermeniz gerekiyor, gerekmeyenler ise almıyor. Sonuçta özün değişmediği hissi var. IO fonksiyonları yine yalnızca IO fonksiyonlarından çağrılabiliyor ve bu da coloring sorunundan çıkamadığı anlamına geliyor. Elbette yeni bir executor da geçirilebilir ama bunun gerçekten istenen şey olup olmadığı şüpheli. Rust'ta da benzer bir şey yapılabilir. Renkli fonksiyon çağrılarının zahmetli olması da aynı şekilde geçerli. Bazı çekirdek kütüphane fonksiyonlarının colored olması meselesi ise Zig/Rust için de aynı değil. Coloring sorununun özü, context'e yani async executor, auth, allocator vb. gerektiren fonksiyonların çağrılırken bu context'in mutlaka sağlanması gerekliliğidir. Zig'in bunu gerçekten çözdüğünü söylemek zor. Yine de Zig'in soyutlaması çok iyi yapılmış ve Rust bu konuda biraz daha zayıf kalıyor. Ama function coloring sorununun kendisi hâlâ duruyor

    • Klasik async function coloring'e kıyasla temel fark şu: Zig'deki 'Io', yalnızca asenkron işlem için kullanılan özel bir değer değil; dosya okuma, sleep, zamanı alma gibi tüm IO için zorunlu olarak gereken bir değer. 'Io' bir fonksiyonun özelliği değil, her yerde bulunabilen sıradan bir değer. Pratikte bu özellik sayesinde coloring sorunu çözülmüş gibi görünüyor. Çoğu kod tabanında IO zaten kapsamın bir yerinde bulunduğu için, yalnızca gerçekten saf hesaplama yapan fonksiyonların IO'ya ihtiyacı kalmıyor. Bir fonksiyon aniden IO'ya ihtiyaç duymaya başlarsa, çoğu durumda bunu doğrudan 'my_thing.io' içinden alıp kullanabiliyorsunuz. Rust'taki gibi her fonksiyona Allocator geçmek zorunda kalmadığınız için uğraştırmıyor. Yani kod yolu değişip IO yapmanız gerekirse, değişikliği tek tek fonksiyonlara yaymanız gerekmeden doğrudan kullanabiliyorsunuz. Teorik olarak function coloring'in hâlâ var olduğuna katılıyorum, ama fiilen neredeyse tüm fonksiyonlar async-colored olmuş oluyor; bu yüzden pratikte sorun neredeyse yok. Nitekim Zig geliştiricileri de Allocator'ı açıkça geçirmenin function coloring kaynaklı bir zahmet oluşturmadığını düşünüyor. 'Io' için de benzer şekilde büyük bir sorun olmayacağını düşünüyorum

    • Bence önemli ana nokta atlanmış. Rust kütüphanelerini kullanırken async/await, tokio, send+sync gibi koşulları mutlaka sağlamak gerekiyor ve API sync ise async uygulamada fiilen işe yaramaz hâle geliyor. Buna karşılık Zig'in IO geçirme yaklaşımı bu sorunu temelden çözüyor. Böylece uğraştırıcı procedural macro'lara veya yapay çoklu sürümlemelere gerek kalmıyor; zaten bu tür yaklaşımlar da kütüphane çoklu sürüm sorununu gerçekten iyi çözmüyor. Rust'ta async/sync karışımıyla ilgili çeşitli tartışmalar var; şu bağlantıda da anlatılıyor: https://nullderef.com/blog/rust-async-sync/. Umarım Zig ileride cooperative scheduling, yüksek performanslı async ve thread-per-core async gibi konuları da iyi çözer

    • Kategori kuramı uzmanı değilim ama sonunda bu tür context yönetimi yoluna girince varılan yer IO monad oluyor. Bu bağlam Context olarak örtük olabilir ama derleyici yardımından düzgün faydalanmak istiyorsanız sistem içinde somut bir varlık olarak ortaya çıkması gerekiyor. Sistem programlama dillerinin büyük hedefleri hep Async ya da coroutine mezarlığında gömüldü, ama Andrew'nun IO monad'ı bir bakıma yeniden keşfedip düzgün uygulaması bu kuşak için umut verici. Gerçek dünya fonksiyonlarının renkleri vardır. Ya net geçiş kuralları koyarsınız ya da C++'taki co_await ve tokio gibi giderek karmaşıklaşan yola saparsınız. Bana göre bu tam olarak ‘The Way’

    • Tüm fonksiyonları kırmızıya ya da maviye boyamanın basit bir hilesi var

      var io: std.Io = undefined;
      
      pub fn main() !void {
        var impl = ...;
        io = impl.io();
      }
      

      io'yu global değişken yapıp kullanırsanız coloring diye dert kalmaz. Şaka bir yana, elbette 'Io' arayüzünü kullanma zorunluluğu biraz sürtünme yaratıyor ama bu, async/await kullanırken ortaya çıkan gerçek friction ile özünde farklı bir mesele. Bana göre function coloring sorununun özü, async anahtar sözcüğünün statik renk ataması yüzünden kod yeniden kullanımını imkânsızlaştırması. Zig'de bir fonksiyonu async yapmak ya da yapmamak fark etmiyor, her durumda IO argümanını alıyor; bu açıdan coloring'in kendisi anlamsızlaşıyor. İkinci olarak, async/await kullanınca stackless coroutine yani derleyici kontrollü stack switching zorunlu oluyor; ama Zig'in yeni IO sistemi içeride async kullansa bile Blocking IO olarak çalışabilecek şekilde düzenlenebiliyor. Bana göre asıl pratik function coloring sorunu bu

    • Go da “ince bir coloring” sorunu yaşıyor. Goroutine kullanırken iptal işlemleri için her zaman context argümanı geçirmek gerekiyor ve birçok kütüphane fonksiyonu da context istiyor; bu da tüm kod tabanına yayılıyor. Teknik olarak context kullanmamak mümkün ama rastgele context.Background geçirmek önerilen bir yaklaşım değil

  • sans-io kavramı Rust vb. dillerde daha önce de tartışıldı; ilgili bağlantılar: https://www.firezone.dev/blog/sans-io, https://sans-io.readthedocs.io/, https://news.ycombinator.com/item?id=40872020

    • Fonksiyon IO metotlarını doğrudan çağırıyorsa, dışarıdan IO'yu ayırmak mümkün olmayan bir yapı oluştuğu için buna sans-io demek zor bence. Bağlantılarda anlatıldığı gibi, byte stream tabanlı protokollerde gerçek sans-io yaklaşımı, implementasyonun yalnızca giriş/çıkış buffer'larıyla uğraşması ve ağdan veri alma kısmının mutlaka çağıran tarafça verilmesi demek. Çıkış için de ya yalnızca buffer'a yazarsınız ya da olay gerçekleştiğinde byte stream'i hemen döndürürsünüz. Dönüş biçimi uygulama tercihidir ama iç buffer, otomatik yanıt gereken durumlarda kullanışlıdır. Esas mesele doğrudan IO yapmayan bir yapı olmasıdır
  • Bence function coloring'in sorunu, stack üzerinde çözseniz de stack'i unwind etseniz de sonunda iki seçenekten birinin kalması. Zig coloring sorununu çözdüğünü iddia ediyor ama IO implementasyonu olarak hâlâ blocking/thread pool/green thread kullanabilmeyi mümkün kılıyor. Oysa bu tür blocking IO zaten baştan sorun olan şey değildi. Global state kullanmama geleneğine uyduğunuz sürece bu düzeyde bir şeyi neredeyse her dilde yapabilirsiniz. Stackless coroutine henüz uygulanmamış durumda; biraz “kalan parçaları da çizersen tamam” hissi veriyor. Eğer gerçekten evrensel fonksiyon çağrısı istiyorsak, bence iki yol var

    • Tüm fonksiyonları async yapmak ve bir argümanla senkron çalışıp çalışmayacağını belirlemek (performans kaybı olur)

    • Her fonksiyonu iki kez derleyip duruma göre uygun olanı çağırmak (kod boyutu artar ve function pointer yönetimi zorlaşır)

      • Çekirdek ekipten değilim ama duyduğum kadarıyla kullanıcılar ve gerçek kullanıcılar semiblocking implementasyonları yeterince deneyip API'yi oturttuktan sonra, tam da o çözümü yani stack jumping tabanlı gerçek coroutine eklemeyi planlıyorlar. Şu anda LLVM'in coroutine state machine derleyicisinin libc ya da malloc bağımlılığı gibi sorunları var. Zig'in yeni io arayüzü userland async/await'i desteklediği için, ileride düzgün bir frame jumping çözümü geldiğinde taşımak kolay olacak ve debug etmek de rahatlayacak. Coroutine işi zor çıkarsa, io API'si de küçük düzeltmelerle dayanabilecek şekilde tutuluyor; yani stackless coroutine'e fazla acele etmiyorlar

      • C#/.NET'teki ValueTask<T> de benzer bir rol oynuyor. İş senkron tamamlanırsa ek yük olmuyor, gerekirse yalnızca o zaman Task<T> olarak kullanılabiliyor. Kod tarafında genelde sadece await yazıyorsunuz; çalışma anında runtime ya da derleyici senkron/asenkron seçimini kendisi yapıyor

  • Zig'i seviyorum ama green thread'e yani fiber/stackful coroutine tarafına odaklanmaları biraz hayal kırıklığı yaratıyor. Rust da 1.0 öncesinde benzer bir Runtime trait'i performans sorunları nedeniyle kaldırmıştı. Aslında OS, dil ve kütüphane ekosistemleri bu yaklaşımın zararlarını defalarca gördü ve bununla ilgili kaynaklar da var: https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1364r0.pdf. Fiber'lar 90'larda ölçeklenebilir eşzamanlılık için popülerdi ama bugün stackless coroutine'ler, OS/donanım ilerlemeleri vb. nedenlerle artık önerilmiyor. Eğer böyle devam ederse Zig, Go benzeri bir performans sınırına çarpabilir ve gerçek bir performans rakibi olmakta zorlanabilir. std.fs'nin performans gereken senaryolarda elde kalmasını umuyorum

    • Green thread'e yani fiber'lara “tamamen yüklendiğimiz” izlenimi yanlış. OP'nin bağlantı verdiği yazıda stackless coroutine tabanlı bir implementasyon beklendiği açıkça belirtiliyor ve buna dair öneri de var: https://github.com/ziglang/zig/issues/23446. Performans önemli ve fiber'lar performans açısından beklentiyi karşılamazsa yaygın çözüm olmayacaktır. Bu yazıda tartışılanlar, stackless coroutine'in varsayılan 'Io' implementasyonu olmasına engel değil

    • Green thread'in performansının kötü olduğu iddiasından emin değilim. Başlıca eşzamanlı sunucu platformlarının hepsi Go, Erlang, Java green thread kullanıyor ya da kullanmaya çalışıyor. Green thread'ler C FFI ile uyumluluk sorunları nedeniyle Rust gibi daha düşük seviyeli diller için uygun olmayabilir ama performansın kendisinin her zaman sorun olduğunu söylemek zor

    • Bu, birçok seçenekten yalnızca biri olduğu için buna ‘all-in’ demek doğru değil. Hangi implementasyonun seçileceğine executable karar verir; kütüphane kodu değil

    • Zig de Rust'ın green thread'i kaldırıp async runtime'a geçmesindekine benzer bir etkiyi hedefliyor. Buradaki temel sezgi, ‘async=IO, IO=async’ fikrini resmileştirmesi. Rust tokio gibi pluggable async runtime'lar sunarken, Zig pluggable IO runtime sunuyor. Sonuçta yönelim, runtime'ı dilden çıkarıp kullanıcı alanında takılabilir hâle getirmek ve herkesin ortak bir arayüz paylaşmasını sağlamak

    • Kaynak (P1364R0) tartışmalıydı ve bana göre belirli bir yaklaşımı ortadan kaldırmak amacıyla motive edilmiş iddialar içeriyordu. Karşı argümanlar için şu bağlantılara da bakılabilir: https://old.reddit.com/r/cpp/comments/1jwlur9/stackful_coroutines_faster_than_stackless/, https://old.reddit.com/r/programming/comments/dgfxde/fibers_arent_useful_for_much_any_more/f3bmpww/

  • Zig gibi bir sistem dilinde, yaygın standart IO işlemlerinde bile runtime polymorphism'i zorunlu kılmak biraz garip geliyor. Çoğu gerçek kullanımda IO implementasyonu statik olarak belirlenebilirken neden runtime overhead dayatılsın ki?

    • IO'da dynamic dispatch overhead'inin pratikte neredeyse önemsiz kalacağını düşünüyorum. IO hedefi ne olduğuna göre değişir elbette ama sonuçta CPU darboğazı olmayan IO vakaları çok daha yaygın. Zaten buna IO-bound deniyor

    • “Neden herkese runtime overhead dayatılıyor?” sorusuna karşılık, çoğu durumda tek tür io kullanan sistemlerde derleyicinin double indirection maliyetini optimize edip ortadan kaldırmasının amaçlandığı anlaşılıyor. Ayrıca IO'da zaten darboğaz başka yerde olduğu için bir seviye daha indirection eklenmesi pek yük oluşturmaz

    • Zig'in felsefesinde binary size daha fazla önemseniyor. Allocator'da da aynı trade-off var; örneğin ArrayListUnmanaged allocator için generic değil, bu yüzden her allocation'da dynamic dispatch oluşuyor. Pratikte dosya allocation'ı ya da write maliyeti, dolaylı çağrı overhead'ini fazlasıyla bastırıyor. Binary boyutuna bu kadar odaklanmak Zig tarzı. Bu arada devirtualization yani dinamik çağrıyı statik çağrıya çeviren optimizasyon biraz şehir efsanesi

    • Runtime polymorphism özünde kötü bir şey değil. Tight loop içinde branch üretmesi ya da derleyicinin inline optimizasyonu yapamaması gibi durumlar yoksa, sorun sayılmaz

  • Yeni io parametresinin her yerde görünmesi çok hoşuma gitmiyor ama farklı implementasyonları thread tabanlı, fiber tabanlı vb. kolayca kullanabilme ve kullanıcıya bir implementasyon dayatmama fikri Allocator arayüzündeki gibi çok hoşuma gidiyor. Genel olarak ciddi bir iyileştirme ve çeşitli stdlib implementasyonları arasında ek overhead olmadan sync/blocking io implementasyonu da sunulursa, Zig'in “kullanmadığın şeyin bedelini ödemezsin” felsefesine tam uymuş olur

    • “Kullanmadığın şeyin bedelini ödemezsin” gerçekten mümkün mü? Takım çok küçük ve son derece disiplinli değilse, eninde sonunda başka biri onu kullanacak ve maliyeti ben de ödeyeceğim. Ayrıca io'yu sürekli geçirmek, gereken yerde sadece çağırmaktan daha uğraştırıcı gibi duruyor
  • Zig'de io.async, asenkronluğu yani işlemlerin sırasının garanti edilmeyebileceğini ama sonucun doğru olacağını ifade ediyor; concurrency'yi ifade etmiyor. Yani async ile io çağrılarının anlamını ayırmış olmaları asıl önemli nokta. Bence bu tasarım çok zekice

  • IO arayüzü sayesinde dil seviyesinde bir vfs Virtual File System oluşturulabilmesi hoşuma gidiyor

    • Örnek koda bakınca güvenlik açısından capability tabanlı güvenliğin de uygulanabileceğini düşündüm. Örneğin yalnızca belirli bir dizin altını okuyabilen bir io instance'ını kütüphaneye vermek gibi. Referans: https://news.ycombinator.com/item?id=44549430
  • Zig öğrenmek için basit bir ssh sunucusu yazmayı denedim. Bu yeni IO/event loop yapısı sayesinde kod akışını çok daha kolay anlayabildim. Andy'ye teşekkürler

    • Yeni tasarımda event loop/io'yu anlamayı hangi yönün kolaylaştırdığını merak ettim
  • Yazı çok iyi yazılmış, okumak çok ilginçti. Özellikle WebAssembly tarafındaki çıkarımları heyecan verici buldum. WASI'yi userspace'te kullanabilmek ve Bring Your Own IO yaklaşımının mümkün olması gerçekten çok ilginç