5 puan yazan GN⁺ 2025-07-20 | 1 yorum | WhatsApp'ta paylaş
  • Asenkronluk ve eşzamanlılık sıkça karıştırılan kavramlardır, ancak farklı anlamlara gelir
  • Asenkronluk, işlerin sıradan bağımsız olarak yürütülebilme olasılığını ifade eder
  • Eşzamanlılık, sistemin birden fazla işi aynı anda ilerletebilme yeteneğini ifade eder
  • Dil ve kütüphane ekosistemlerinde bu iki kavramın net biçimde ayrılmaması verimsizlik ve karmaşıklık yaratır
  • Zig dili, asenkronluk ile eşzamanlılığı ayırarak kod tekrarı olmadan senkron ve asenkron kodun bir arada bulunmasını mümkün kılar

Giriş: Asenkronluk ile eşzamanlılığı ayırma gereği

Rob Pike'ın ünlü sunumu sayesinde “eşzamanlılık paralellik değildir” cümlesi iyi biliniyor, ancak bundan daha pratik açıdan önemli bir nokta daha var: “asenkronluk” kavramının gerekliliği. Vikipedi tanımına göre,

  • Eşzamanlılık: Sistemin aynı anda birden fazla işi zaman paylaşımıyla veya paralel olarak işleyebilme yeteneği
  • Paralel hesaplama: Birden fazla işin gerçek fiziksel düzeyde aynı anda çalıştırılması
    Bunların dışında, gözden kaçırdığımız önemli kavram “asenkronluk”tur.

Örnek 1: İki dosyayı kaydetme

İki dosyayı (A, B) kaydederken sıra önemli değilse,

io.async(saveFileA, .{io})
io.async(saveFileB, .{io})
  • Önce A'yı kaydetmek ya da önce B'yi kaydetmek fark etmez; aralarda dönüşümlü kaydetmek de sorun yaratmaz
  • Hatta önce A dosyasını tamamen kaydedip sonra B'ye başlamak bile kod açısından doğrudur

Örnek 2: İki soket (sunucu, istemci)

Aynı program içinde bir TCP sunucusu oluşturup istemciyi bağlamak gerektiğinde,

io.async(Server.accept, .{server, io})
io.async(Client.connect, .{client, io})
  • Bu durumda iki işin yürütülmesinin mutlaka örtüşecek şekilde ilerlemesi gerekir
  • Yani sunucu bağlantıyı kabul ederken istemcinin de bağlantı kurmayı denemesi gerekir
  • İlk dosya örneğindeki gibi seri biçimde işlenirse amaçlanan davranış ortaya çıkmaz

Kavramların özeti

Asenkronluk, eşzamanlılık ve paralellik kavramları şu şekilde tanımlanır:

  • Asenkronluk (asynchrony) : İşlerin sıra dışı yürütülse bile doğru sonucun çıkmasını sağlayan özellik
  • Eşzamanlılık (concurrency) : İster paralel ister bölünmüş yürütme olsun, birden fazla işi aynı anda ilerletebilme yeteneği
  • Paralellik (parallelism) : Birden fazla işin fiziksel olarak gerçek zamanlı biçimde aynı anda yürütülme yeteneği

Dosya kaydetme ile soket bağlantısı örneklerinin ikisi de asenkrondur, ancak ikincisinde (sunucu-istemci) eşzamanlılık zorunludur

Asenkronluk ile eşzamanlılığı ayırmanın faydası

Bu ayrım yapılmazsa şu sorunlar ortaya çıkar:

  • Kütüphane geliştiricileri asenkron/senkron sürümlerin kodunu iki kez yazmak zorunda kalır (ör. redis-py vs asyncio-redis)
  • Kullanıcılar için asenkron kod “bulaşıcı” hale gelir; yalnızca tek bir asenkron kütüphane bağımlılığı bile tüm projeyi asenkrona çevirmeyi gerektiren bir rahatsızlık yaratır
  • Bundan kaçınmak için çeşitli dolaylı çözümler üretilir ve bunlar çoğu zaman *deadlock* ile verimsizliğe yol açar

Bu yüzden, iki kavramın net biçimde ayrılması hem kütüphaneler hem de kullanıcılar için büyük avantaj sağlar

Zig: asenkronluk ile eşzamanlılığın ayrılması

Zig dili io.async aracılığıyla asenkronluk kullanır, ancak bu eşzamanlılığı garanti etmez

  • Yani io.async kullanılsa bile içeride tek iş parçacıklı, blocking modda çalışmak mümkündür
  • Örneğin
    io.async(saveFileA, .{io})
    io.async(saveFileB, .{io})
    
    bu kod, blocking bir ortamda
    saveFileA(io)
    saveFileB(io)
    
    ile aynı şekilde davranabilir
  • Böylece kütüphane geliştiricisi io.async kullansa bile kullanıcı isterse bunu sıralı blocking IO olarak çalıştırma esnekliğini korur

Eşzamanlılığın devreye alınması ve görev geçişi (scheduling) mekanizması

Eşzamanlılığın gerekli olduğu durumlarda, gerçekten etkili bir çalışma için şunlar gerekir:

  1. Blocking olmayan event tabanlı IO kullanımı (epoll, io_uring vb.)
  2. Görev geçişi (switching) primitive'lerinin kullanımı (ör. yield)
  • Örneğin Zig, green thread ortamında görev geçişi için stack swapping tekniğini kullanır
  • OS düzeyindeki thread scheduling'e benzer şekilde CPU register'ları, stack ve diğer durum bilgileri kaydedilip geri yüklenerek birden fazla görev arasında geçiş yapılır
  • Bu tür bir geçiş mekanizması olmadan asenkron kodu gerçekten eşzamanlı olarak schedule etmek mümkün değildir
  • Stackless coroutine uygulamaları da (ör. suspend, resume) aynı ilkeye dayanır

Senkron kod ile asenkron kodun bir arada bulunması

Aşağıdaki gibi saveData iki kez io.async ile çalıştırılırsa,

io.async(saveData, .{io, "a", "b"})
io.async(saveData, .{io, "c", "d"})
  • İki iş birbiriyle asenkron olduğu için, içte senkron biçimde yazılmış fonksiyonlar olsa bile bunlar doğal biçimde eşzamanlılık bağlamında schedule edilebilir
  • Kullanıcı ya da kütüphane geliştiricisi kod tekrarı olmadan senkron/asenkron fonksiyonları birlikte kullanabilir

Eşzamanlılığın 'zorunlu' olduğu durumları belirtmek

Belirli fonksiyonlarda (ör. TCP sunucusunun accept işlemi) çalıştırma anında açıkça eşzamanlılık gerektiğini kodda ifade etmek gerekir

  • Zig bunu io.asyncConcurrent gibi açık fonksiyonlarla ayırır
  • Bu yaklaşım, ilgili iş çalıştığı ortamda eşzamanlılık desteklenmiyorsa hata üretir
  • Asenkron amaçlı io.async'den farklı olarak burada eşzamanlılık garantisi zorunlu olduğundan başarısız olabilen bir fonksiyon olarak uygulanır

Sonuç

  • Asenkronluk ile eşzamanlılık tamamen farklı kavramlardır ve net biçimde ayrılmalıdır
  • Senkron kod ile asenkron kodun bir arada bulunması mümkündür
  • Zig'in asenkron/eşzamanlılık modeli, kod tekrarı olmadan bu iki dünyayı birlikte kullanmayı sağlar
  • Bu yapı, Go gibi diğer dillere de uygulanmıştır ve async/await'in bulaşıcılığını aşmanın bir yolunu gösterir
  • Zig'in yeni async I/O tasarımıyla birlikte, ileride daha sezgisel bir eşzamanlılık/asenkron programlama ortamı beklenebilir

1 yorum

 
GN⁺ 2025-07-20
Hacker News görüşü
  • async tanımını yapmak gerçekten zor geliyor; ben de JavaScript'te async'i tasarlayan kişilerden biriydim ve bu yazıda sunulan tanıma katılmıyorum. Sırf async olduğu için bir şey doğru çalışmaz. Async kodda da hâlâ çeşitli kullanıcı seviyesi race condition türleri ortaya çıkabilir; dil async/await desteklese de desteklemese de durum aynı. Benim yakın zamanda vardığım tanım, async'in “eşzamanlılık için açıkça yapılandırılmış kod” olduğudur. Bu bakış açısının da hâlâ biraz daha işlenmesi gerekiyor. Bununla ilgili bizzat topladığım notlar için Quite a few words about async yazısına bakılabilir.

    • Asynchronism gibi soyut bir kavram ile bunun pratikteki gerçekleştirimini ayırmanın önemli olduğunu düşünüyorum; ikincisi hem dil düzeyindeki soyutlamaları hem de mekanik koordinasyon araçlarını kapsar. En üst soyutlama düzeyinde synchronism'in karşıtı doğrudan asynchronism'dir. Genelde birden fazla öznenin birlikte çalışması gerektiğinde — örneğin bir iş bitmeden diğerinin ilerleyememesi gibi — bunun ne zaman olacağının bilinmemesi ya da tanımlı olmaması asıl asenkronluk unsurudur. Bu tanımın kendisi zor değil; sorun, dil düzeyinde bu soyutlamayı tasarlarken ortaya çıkan bilişsel yükte.

    • Bu konuya çok derin girmiş değilim ama bana göre async kod, normalde blocking olan işleri non-blocking hâle getirerek başka işlerin aynı anda ilerlemesine imkân tanır. Özellikle benim kullanımımda, gömülü döngülerde uzun süre blocking kalan kod I/O'yu bozabiliyor ve gözle ya da kulakla fark edilen hatalara yol açabiliyor; bu yüzden bu bakış açısı bana çok net geliyor.

    • En başta async'i tanımlamak zorunda olup olmadığımızdan bile emin değilim. Bunu tanımlamanın zor olmasının nedeni, tek bir kavrama tam oturan bir şey olmaması olabilir. Async'i ya da event loop'u ille de tanımlamak gerekip gerekmediğinden de şüpheliyim. Gerçek paralel işlemenin mümkün olduğu fiziksel çip tarafında benim bilmediğim daha pek çok kavram vardır. Bana “user finger” (parmak dokunuşu vb.), “quickies” (çok kısa sürede biten işler), job queue ve blocking/non-blocking API'ler yetiyor. Amacıma ulaşmak için non-blocking API daha iyi, çünkü uzun süren işleri alt sisteme bırakıp ben sadece veri kaydetme gibi bir “quicky” yazarım; başarı ve başarısızlık durumları için de başka quicky'ler tanımlarım. Sync ve async ayrımı bana pek yardımcı olmuyor. Tabii başkaları konuşurken kavramı anlamam gerekiyor. Özünde async'in non-blocking API olduğunu düşünüyorum. Async programlama modeli de aslında (çalışma süresi açısından) küçük ve atomik blocking işleri “kaotik ve deterministik olmayan” olaylara göre yazmak demek. Sistemin içinde ne olursa olsun, tarayıcının, işletim sisteminin ya da cihazın çoklu yürütme birimleri ve iyi bir scheduler sunduğuna güveniyorum. Async benim için muğlak tanımlı bir kavram; tanımlanabilse bile bunun ne kadar faydalı olacağından emin değilim. Buna karşılık event'ler, yazdığım işlerin blocking doğası, function closure'ları ve bir API kullanırken hangi işlerin başka bir job'a bölündüğü gibi kavramlar çok daha pratik. “callback” terimi de başlangıçta çok kafa karıştırıcıydı. Kodun orada durduğunu sanıyordum ama aslında o kısmı sonuna kadar çalıştırıyor ve sonra “callback” çağrıldığında hangi kodun çalışacağını, hangi bilgilere erişebileceğini çok net anlaman gerekiyor. Açıkçası bu hem kaos hem de dahiyane bir fikir. “async”in kendisinden çok, temel model yani event'ler, blocking işler, job queue ve non-blocking API daha basit. Bir de benim ne yaptığımı ve tarayıcı/işletim sistemi vb. tarafın ne yaptığını anlamak oldukça önemli. Örneğin C++ concurrent modeli tanımlar ama gerçek yürütmeyi işletim sistemi yapar. JS'de ise non-blocking API ile tarayıcıya ya da Node'a “muhtemelen” concurrency istediğini bildirirsin; onlar da bunu içeride concurrent biçimde işler. En önemli şey, her işi kısa tutmak (<50ms) ve niyetini non-blocking API ile ifade edebilmektir. C++ ya da Rust, işletim sistemine gerçek task'leri concurrent biçimde çalıştırmasını söylediği için fiziksel olarak tek thread olsa bile UI tepkiselliği korunur. Sonuçta async programcının görevi “iyi bir UX modeli” kurmak ve event'leri quicky'lere iyi eşlemektir.

  • Yazarın “yield etme” kavramını eşzamanlılık tanımından çıkarıp yeni bir “asynchrony” terimine koymuş gibi görünüyor; hatta bu olmadan concurrency'nin çökeceğini öne sürüyor. Bana göre concurrency'de yield etme zaten gereklidir ve kavramın içinde vardır. Önemli bir fikir ama bunu yeni bir terimle ayrıca ayırmak sadece daha fazla kafa karışıklığı yaratıyor.

    • Bana göre 1:1 paralellik, yield etme içermeyen bir concurrency türü. Bunun dışındaki bütün paralel olmayan concurrency biçimleri, hangi düzeyde olursa olsun yürütmeyi bir noktada bırakmak zorundadır; instruction düzeyinde bile böyle. Örneğin CUDA'da aynı warp içindeki dallanmış thread'ler komutları dönüşümlü yürüttüğü için bir dal ötekini bloke edebilir.

    • Alıntılanan yazıda zaten açıkça “yield etme concurrency'nin bir kavramıdır” denildiğini özellikle vurguluyorum.

    • Concurrency zorunlu olarak yield etmeyi ifade etmez. Senkron mantık açık bir synchronism gerektirir ve yield etme bunun sadece bir yolu olabilir. Benim async mantık derken kastettiğim, synchronism ya da yield etme olmadan çalışan concurrency'dir. Pratik açıdan bakarsak, concurrency ya da async mantık von Neumann makinelerinde tam anlamıyla var olmaz.

  • Bu bağlamda async, istek hazırlama/gönderme ile sonuç toplama işlemlerini ayıran bir soyutlamadır. Bu sayede birden fazla isteği gönderdikten sonra sonuçlarını daha sonra kontrol etmek mümkün olur. Concurrent bir uygulamaya izin verir ama bunu zorunlu kılmaz. Yine de bu soyutlamanın amacı concurrency elde etmektir; concurrency yoksa beklenen fayda da yoktur. Bazı async soyutlamaları, en azından asgari concurrency olmadan hiç gerçekleştirilemez. Örneğin callback yaklaşımı tek thread'de taklit edilebilir ama non-recursive bir mutex tutulurken deadlock üretmesi gibi sınırları vardır. Yani concurrency'siz bir async soyutlama kaçınılmaz olarak başarısız olur. İstekte bulunan taraf mutex'i elinde tutarak isteği yapar ve unlock etmeden önce callback çalışırsa unlock hiçbir zaman gerçekleşmeyebilir. En azından ayrı bir thread sayesinde isteği yapan tarafın unlock noktasına ulaşmasına izin vermek gerekir.

    • Katılıyorum. Yazıdaki sunucu-istemci örneği sadece tek bir örnek ve senin sözünü ettiğin durum bambaşka türde bir çözüm gerektiriyor. İleride buna benzer daha çok vaka göreceğimizi düşünüyorum. Sonuç olarak async kullanırken concurrency'yi her zaman garanti etmek gerekiyor.
  • "Cooperative multitasking, preemptive değildir." “Async” terimi genelde “tek thread, cooperative multitasking (açık yield noktaları) ve event temelli yapı”, ayrıca dış işlemlerin concurrent biçimde çalışıp sonucu event olarak bildirmesi anlamına gelir. Çoklu thread ya da concurrent yürütme modellerinde async'in özel bir anlamı kalmaz; o thread block olsa bile program genel olarak ilerlemeye devam eder. Yield noktalarının açıkça belirtilmesi de gerekmez.

    • Rust, C#, F#, OCaml (5+) gibi diller hem OS thread'lerini hem de async'i destekliyor. OS thread'leri CPU-bound işler için, async ise IO-bound işler için uygun. Async'in veya Go tarzı M:N scheduling'in en büyük artısı, yeterli bellek olduğu sürece task/goroutine sayısını rahatça artırabilmek. OS thread yaklaşımında context switch yükü, thread/bellek yetersizliği gibi sorunlar olduğu için iş IO-bound sınırını geçince bile deadlock benzeri problemler çıkabiliyor.
  • Zig'in yeni IO fikri genel uygulama geliştirme için yenilikçi görünüyor. Stackless coroutine istemeyenler için de ideal olabilir. Ama kütüphane yazarken hata üretmeye daha açık gibi duruyor. Kütüphane yazarı, verilen IO'nun tek thread mi çoklu thread mi olduğunu, event tabanlı IO olup olmadığını anlamakta zorlanabilir. Concurrency/asynchrony/parallelism ile ilgili kod, IO yığınını tamamen bildiğinde bile yazması zor; IO dışarıdan verilen bir yapıdaysa bu zorluk katlanıyor. IO arayüzü “küçük bir OS” gibi devasa hâle gelirse test edilmesi gereken senaryolar da patlar. Arayüzün sunduğu async primitiflerle gerçek edge case'lerin hepsini yönetip yönetemeyeceğimizden emin değilim. Farklı IO uygulamalarını desteklemek için kodun çok “defansif” yazılması ve her zaman en paralel IO'nun varsayılması gerekecek gibi görünüyor. Özellikle stackless coroutine'lerle bu yaklaşımı birleştirmek kolay olmayacaktır. Gereksiz coroutine spawn'larını azaltmak için coroutine'leri açıkça poll etmek gerekir, ama çoğu geliştirici böyle bir kodu elle yazmaz. Sonunda yapı yine normal async/await koduna benzer bir yere varacak gibi. Dynamic dispatch ve Zig'in aşağıdan yukarı tasarım eğilimi de düşünülünce sonuçta oldukça yüksek seviyeli bir dil ortaya çıkabilir. Henüz ortada gerçek kullanım örnekleri yokken buna “tavizsiz” yaklaşım demek biraz iddialı. Bunun gerçek değerlendirmesi ancak birkaç yıllık kullanımdan sonra yapılabilir.

    • Stackless coroutine desteği zaten gelecek; WASM hedeflerini desteklemek için buna ihtiyaç var, yani kesinlikle eklenecek. Dynamic dispatch yalnızca iki ya da daha fazla IO implementasyonu olduğunda kullanılıyor; tek bir tane varsa doğrudan çağrıya indirgeniyor. Henüz sahada doğrulanmadığı için “tavizsiz” ifadesinin erken olduğunu düşünüyorum. Jai dilinde benzer bir modelin başarıyla kullanıldığını duydum (açık context geçişi yerine örtük bir IO context farkıyla), ama buna da gerçek dünyada kanıtlanmış demek zor.

    • Senkron ve asenkron yürütmeyi birlikte desteklemek için kodun her zaman en paralel IO'yu varsayması gerektiği konusunda katılıyorum. Ama düşük seviyeli IO event handler tarafında async düzgün uygulanmışsa, geri kalan her yerde aynı ilkeyi izlemek yeterli olur. En kötü durumda kod sadece sıralı biçimde, yani daha yavaş çalışır; ama race/deadlock sorunlarına düşmez.

  • İki ayrı kütüphane kullanmak zorunda bırakmaması açısından Zig'in fikrini çok beğeniyorum. Yine de async kodun test edilmesi beni hep düşündürüyor. Bugün geçen bir testin, çalışma sırasında gerçekleşebilecek tüm senaryoları ve sıralamaları gerçekten kapsadığından nasıl emin olabiliriz bilmiyorum. Thread programlarında da aynı sorun var ama çoklu thread kodunu yazmak ve debug etmek her zaman daha zor. Ben mümkün oldukça thread kullanmaktan kaçınıyorum. Asıl sorun, ‘geliştiricinin async/thread ortamını gerçekten anlamasını sağlamak’. Yakın zamanda yarısı JS yarısı Python olan bir sistem üzerinde çalışan bir ekiple çalıştım; büyük bir kod tabanını async ve threaded hâle getirmişlerdi ama Global Interpreter Lock (GIL)'in ne olduğunu bile bilmiyorlardı. Benim söylediklerim onlara sadece dırdır gibi gelmiş olmalı. Üstelik testleri, kodu gerçekten bozsan bile hep geçiyordu. mangum, HTTP request bittiğinde background ve async işleri zorla tamamlatıyor ama bunu da bilmiyorlardı. Böyle şeyleri anlatsan bile çoğu kişinin umurunda olmuyor. Bilmekten daha önemlisi, başkalarının buna dikkat edip etmemesi galiba.

    • Zig'de Io için test implementasyonları eklenmesi planlanıyor. Böylece paralel yürütme modeli altında fuzz test gibi stres testleri yapmak da mümkün olacak. Ama asıl nokta şu: çoğu kütüphane kodunun io.async ya da io.asyncConcurrent'i doğrudan çağırması gerekmeyecek. Örneğin veritabanı kütüphanelerinin büyük kısmı saf senkron kod olarak yazılabilir. Uygulama geliştiricisi daha sonra bunu io.async(writeToDb), io.async(doOtherThing) gibi çağrılarla kolayca asenkron hâle getirebilir. Bu, async/await'in tüm koda serpiştirilmesinden daha az hataya açık ve anlaması çok daha kolay.

    • Katılıyorum; async ve çoklu thread kodunda tüm interleaving'leri test etmek kötü şöhretli derecede zordur. Fuzzer ya da concurrency test çerçeveleri kullansan bile, gerçek üretim ortamında yaşananlardan ders almadan tam güven duymak güç. Dağıtık sistemlerde bu daha da kötüleşiyor. Örneğin webhook altyapısı tasarlarken sadece kendi kodundaki async değil; ağ retry'ları, timeout'lar, kısmi başarısızlıklar gibi dış etkenler de işin içine giriyor. Yüksek concurrency ortamında retry, deduplication ve idempotency garantisi başlı başına bir mühendislik meselesi oluyor. Bu yüzden Vartiq.com gibi uzman servisler gerekli olabiliyor (orada çalışıyorum). Böyle servisler operasyonel concurrency karmaşıklığını bir ölçüde soyutlayıp blast radius'u azaltıyor ama kendi kodumdaki async test sorununu ortadan kaldırmıyor. Sonuçta async, threading ve dağıtık concurrency riskleri birbirini büyütüyor; bu yüzden iletişim ve sistem tasarımı, herhangi bir sözdizimi ya da kütüphaneden daha önemli.

  • Yazarın concurrency tanımında bir karışıklık olduğunu düşünüyorum; Lamport'un makalesi faydalı olabilir.

    • Sadece makale bağlantısı bırakmayın, biraz da açıklayın lütfen. Bana göre tanım kendi içinde fena değildi. Mesela asynchrony: işler sıralı yürümese de doğru sonuç çıkıyorsa bu asenkronluktur. Concurrency: ister paralellik ister task switching yoluyla olsun, bir sistemin birden fazla işi aynı anda ilerletebilme özelliği. Parallelism: fiziksel düzeyde gerçekten iki ya da daha fazla işin aynı anda çalışmasıdır.

    • Bu yüzden ben bu terimleri kullanmayı tamamen bıraktım. Kiminle konuşsan anlam farklı oluyor; terimlerin kendisi iletişim açısından anlamsızlaşıyor.

    • Yazar da blog yazısında bu terimlerin mevcut tanımları olduğunu bildiğini söylüyor. Yani yaptığı şey yeni bir tanım önermek. O tanım kendi içinde tutarlıysa bu yeterli olabilir; fark sadece okuyucunun bunu kabul edip etmeyeceğinde.

    • Lamport makalesinin yarısı çoğu dilde kavramsal olarak ifade bile edilemiyor. Thread oluşturmak, total order ya da partial order tartışmasına gireceğin anlamına gelmiyor. Böyle tartışmalar daha çok TLA+ ile protokol tasarlarken gerekiyor. Zig async API'sinde “yalnızca asenkron yürütme ortamında çalışır” türü bir fonksiyonun derleme hatası vermesini yeni bir teori seviyesine çıkarmak gereksiz.

  • “Asynchrony” teriminin gerçekten gerekli olup olmadığını anlamanın iyi bir yolu, bunun yalnızca tek bir dil ya da modele değil, farklı concurrency modellerine de faydalı olup olmadığına bakmaktır. Örneğin Haskell, Erlang, OCaml, Scheme, Rust, Go gibi çok farklı ortamlarda ortak olarak işe yarayan bir terimse daha değerlidir. Genel olarak cooperative scheduling devreye girdiğinde, sistemin tamamı tek bir kod parçası yüzünden kilitlenme ya da gecikme gibi sorunlara daha açık olur ve çok daha fazla dikkat ister. Preemptive scheduling olduğunda bu problemlerin büyük kısmı ortadan kalkar. Tüm sistemin kilitlenmesi mümkün olmadığından sorun kümesi ciddi biçimde küçülür.

  • Bu durumda “asynchrony” bence uygun kelime değil; zaten iyi tanımlanmış matematiksel bir terim olan “commutativity” var. Bazı işlemlerde sıra önemli değildir (toplama, çarpma gibi), bazılarında ise önemlidir (çıkarma, bölme gibi). Normalde kodda işlem sırası satır numaralarıyla, yani yukarıdan aşağıya ifade edilir; async kodda ise bu sıra bozulur. Bu şekilde yazılmış asyncConcurrent(...) doğal olarak çok kafa karıştırıcı olabilir. Blog yazısındaki fikri tam olarak özümsemediysen ne anlama geldiğini çıkarmak zor. Zig'de (ve sevdiğim Rust'ta da) bu tür “hipster” yaklaşımlar sık görünüyor. Ya Rust'ın lifetime'ları gibi, prosedürel (async tabanlı) bir commutativity/sıralama sistemini açıkça kurmak gerekir ya da insanların alışık olduğu şeyleri kullanmak daha iyidir.

    • asyncConcurrent(...) kafa karıştırıyor” yorumuna katılmıyorum. Blog yazısının temel fikrini içselleştirirsen hiç karışık değil. O fikri öğrenmeye değip değmeyeceği ayrı konu. Gerçekte insanlar bunu içselleştirip bolca pratik yapacak ve zaman içinde bunun sahada iyi bir fikir olup olmadığını göreceğiz. Ayrıca “commutativity”yi başka bir şeyin yerine koymak Zig'de daha da karıştırıcı olabilir; çünkü Zig'de gerçekten commutative olan operatörler var. Mesela f() + g() ifadesinde toplama commutative diye Zig bunu paralel çalıştırabilir mi gibi yanlış sorular doğabilir. Yürütme sırası ile commutativity tamamen farklı şeyler; bunları ayırmak gerekir.

    • Teknik olarak commutativity, (ikili) işlemlere ait bir özelliktir. connect ve accept gibi iki async ifadenin commute ettiğini söylediğinde hemen “hangi işleme göre?” sorusu doğar. Şu an için bind (>>=) operatörü ya da .then(...) buna en yakın rolü üstleniyor olabilir, ama bu hâlâ daha çok sezgisel bir alan.

    • Asenkronluk, kısmi sıralamaya da izin verir. İki işlemin sonuçlarının aynı sırayla emekliye ayrılması gerekse bile bu, gerçek yürütme sırasından bağımsız olabilir. Örneğin çıkarma commutative değildir ama bakiye hesabını ve düşülecek tutarı iki ayrı sorgu olarak paralel yürütüp, sonuçları daha sonra doğru sırayla uygulamak mümkündür.

    • Başka bir terimin bu kavramı kapsıyor olması, onun “asynchrony”den daha iyi bir kelime olduğu anlamına gelmez. “commutativity” okumada da duymada da yazmada da hantaldır; asynchrony çok daha tanıdık geliyor.

    • Commutativity iddiasının bir sınırı da var. A ve B ayrı ayrı C ile commute ediyorsa ABC = CAB olabilir, ama bundan ACB'nin de mutlaka aynı olduğu çıkmaz. Async durumda ise ABC = ACB = CAB hepsinin aynı olması gerekir. Bunun için yerleşik başka bir matematik terimi var mı bilmiyorum.

  • Bir ağ programcısı olarak çok fazla concurrency, parallelism ve async kod yazdım; bu yazı bana biraz kafa karıştırıcı geliyor. Sanki delikleri olan bir soyutlamanın üzerinde cevap aramaya çalışıyor gibi. Araç ya da implementasyonun kendisi hatalıysa bu kadar kolay “bozulabilmesi” zaten sorun. Gerçi çoklu thread kodunu debug etmek de oldukça eğlenceli; başkalarının bu tür multithread canavarlarından bu kadar korkmasını görmek bana tersine keyif veriyor.