2 पॉइंट द्वारा GN⁺ 2025-07-14 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Zig के नए asynchronous I/O interface की शुरुआत से, I/O implementation का तरीका caller सीधे चुन और inject कर सकता है
  • नया डिज़ाइन किया गया Io interface एक साथ asynchrony और parallelism दोनों को support करता है, और code reusability व optimization पर केंद्रित है
  • Blocking I/O, event loop, thread pool, green threads, stackless coroutines जैसी standard library implementations उपलब्ध कराने की योजना है
  • नए API के जरिए future cancellation और resource management, buffering, और granular input/output behavior संभव होगा
  • मौजूदा function coloring समस्या को हल करके, एक ही library से synchronous/asynchronous operation दोनों को optimize करना संभव हो जाता है

अवलोकन

Zig ने हाल ही में एक नया asynchronous I/O interface डिज़ाइन किया है, जिससे उसका विकास I/O कार्यों की flexibility और parallelism support पर अधिक केंद्रित हो गया है। यह बदलाव मौजूदा async/await paradigm को अलग करते हुए इस तरह बनाया गया है कि वास्तविक प्रोग्राम लेखक और अधिक विविध I/O strategies अपना सकें।

नया I/O interface

पहले I/O से जुड़े objects को code के भीतर सीधे बनाया और उपयोग किया जाता था, लेकिन अब Io interface को caller inject करेगा।

  • यह तरीका Allocator pattern जैसा है, जहाँ calling side I/O की concrete implementation चुनकर inject करती है
  • बाहरी package code पर भी एक consistent तरीके से I/O strategy लागू की जा सकती है

मुख्य बदलाव

  • Io interface अब concurrency operations भी संभालता है
  • अगर code concurrency को सही तरह व्यक्त करता है, तो Io implementation के अनुसार parallelism भी प्रदान की जा सकती है

उदाहरण code

  • concurrency के बिना (serial) code और io.asyncawait के जरिए parallelism की संभावना व्यक्त करने वाले code, इन दोनों की तुलना की गई है
    • serial code: दो files में बारी-बारी से save, parallelism के अवसर का उपयोग नहीं
    • parallel code: futures का उपयोग कर file save, asynchronous event loop में अधिक कुशलता से कार्य करता है

await और try का संयोजन

  • await और try को साथ उपयोग करने पर, एक future में error आने पर दूसरे future के resources वापस न कर पाने की समस्या होती है
  • defer और future.cancel से उचित cancellation और cleanup को स्पष्ट रूप से संभाला जा सकता है

Future.cancel API

  • Future.cancel() और Future.await() idempotent हैं, यानी इन्हें कई बार कॉल करने पर भी side effect नहीं होता
  • पहले से complete हो चुके future पर cancel कॉल करने पर केवल resources release होते हैं, और जो काम पूरे नहीं हुए वे error.Canceled लौटाते हैं

standard library I/O implementations

Io interface runtime polymorphism पर आधारित interface है, जिसे सीधे implement किया जा सकता है या third-party packages की implementations का उपयोग किया जा सकता है। Zig की standard library विभिन्न प्रकार की I/O implementations देने की योजना रखती है।

  • Blocking I/O: बस मौजूदा C-style blocking input/output का उपयोग, कोई अतिरिक्त overhead नहीं
  • thread pool: Blocking I/O को OS thread pool में बाँटना, जिससे कुछ parallelism मिलती है। network clients जैसे मामलों में optimization की ज़रूरत हो सकती है
  • green threads: Linux के io_uring जैसे asynchronous system calls का उपयोग कर, OS threads पर कई green (lightweight) threads को संभालना। platform support आवश्यक (x86_64 Linux प्राथमिक)
  • stackless coroutines: state machine आधारित coroutines जिन्हें explicit stack की ज़रूरत नहीं। WASM जैसी कुछ platforms के साथ compatibility के लिए। Zig compiler में propriety convention को फिर से लाने की आवश्यकता है

डिज़ाइन लक्ष्य

code reusability

asynchronous I/O की सबसे बड़ी समस्या code reusability है। दूसरी भाषाओं में blocking/async functions अलग-अलग मौजूद होते हैं, जिससे code विभाजित हो जाता है। Zig का तरीका:

  • एक ही library synchronous और asynchronous modes दोनों को प्रभावी ढंग से support कर सकती है
  • async/await, ‘function coloring’ को हटाता है, और Io system के जरिए runtime पर भी अलग-अलग execution models पर निर्भर नहीं रहना पड़ता

निष्कर्षतः function coloring समस्या पूरी तरह हल हो जाती है

optimization

  • नया Io interface non-generic, vtable-आधारित virtual call तरीके से implement किया गया है
  • virtual calls code bloat को कम करते हैं, लेकिन runtime पर थोड़ा overhead होता है। optimized builds में यदि केवल एक Io implementation हो, तो de-virtualization (virtual call removal) संभव है
  • कई Io implementations होने पर virtual calls बने रहते हैं, ताकि code duplication से बचा जा सके

buffering strategy

  • पहले हर implementation (reader/writer) buffering संभालती थी, लेकिन अब Reader और Writer interface स्तर पर buffering की जाती है
  • buffer flush को छोड़कर virtual call path से नहीं गुजरना पड़ता, इसलिए optimization आसान हो जाती है

semantic I/O operations

Writer interface कुछ खास optimization operations के लिए दो नए primitives देता है

  • sendFile: POSIX sendfile से प्रेरित, file descriptors के बीच data movement kernel के भीतर ही करता है। memory copy न्यूनतम होती है
  • drain: Vectorized write + splatting support। कई data segments को एक साथ भेजना, जिसे writev system call में बदला जा सकता है। splat parameter के जरिए अंतिम element को दोहराकर उपयोग किया जा सकता है (जैसे compression आदि streams में)

roadmap

इस बदलाव का कुछ हिस्सा Zig 0.15.0 से शामिल होगा, लेकिन library में बड़े पैमाने पर पुनर्गठन की आवश्यकता होने के कारण पूरा लागू होना अगली release तक इंतज़ार करेगा। SSL/TLS, HTTP server/client जैसे प्रमुख modules को भी नए Io system के अनुसार फिर से डिज़ाइन किया जाएगा

FAQ

Q: Zig एक low-level language है, फिर async इतना महत्वपूर्ण क्यों है?

  • Zig का लक्ष्य robustness, optimization, और reusability है
  • Non-blocking input/output को standardize करके, दूसरी libraries और third-party code को भी समग्र I/O strategy के अनुसार समायोजित किया जा सकता है और reusability सुनिश्चित होती है

Q: क्या package authors को अब हर code में async का उपयोग करना होगा?

  • नहीं। हर code को concurrency व्यक्त करने की आवश्यकता नहीं है
  • सामान्य sequential code भी उपयोगकर्ता द्वारा चुनी गई I/O strategy के अनुसार काम करेगा

Q: क्या किसी भी execution model को plugin की तरह जोड़ देने से सब कुछ अपने-आप सही चलेगा?

  • अधिकांश मामलों में हाँ
  • लेकिन code में programming errors (जैसे concurrent tasks की आवश्यक शर्तें पूरी न होना) हों, तो सही संचालन संभव नहीं होगा

execution examples के साथ, asynchrony और parallelism के अंतर तथा सही execution flow डिज़ाइन की आवश्यकता का भी उल्लेख किया गया है

निष्कर्ष

नए Io interface की शुरुआत के साथ Zig ने input/output strategy चुनने की flexibility, code reusability, और optimization की संभावना को काफी बढ़ा दिया है। इससे asynchronous/synchronous आधारित function लिखने की बाधाओं के बिना, developers concurrency और parallelism की संरचना को अधिक स्पष्ट रूप से व्यक्त कर सकते हैं और विभिन्न platforms व execution models के लिए प्रभावी ढंग से अनुकूलित हो सकते हैं।

1 टिप्पणियां

 
GN⁺ 2025-07-14
Hacker News टिप्पणियाँ
  • मैं इस बात को फिर से उठाना चाहता हूँ। लेख में तो यहाँ तक कहा गया है कि Zig ने function coloring की समस्या पूरी तरह हल कर दी है, लेकिन मैं सहमत नहीं हूँ। मशहूर "What color is your function?" लेख के 5 नियमों को फिर से देखें तो Zig में भले async/sync/red/blue जैसी coloring न हो, लेकिन आखिरकार सिर्फ़ दो ही case रहते हैं: IO functions और non-IO functions। function call का तरीका coloring के हिसाब से बदलने वाली समस्या को तकनीकी रूप से हल कर दिया गया हो, फिर भी जिन functions को IO चाहिए उन्हें IO argument के रूप में देना पड़ता है, और जिन्हें नहीं चाहिए वे नहीं लेते। इसलिए लगता है कि मूल बात बदली नहीं है। IO function अब भी सिर्फ़ IO function से ही call किया जा सकता है, और यह भी coloring समस्या से बाहर नहीं निकलता। हाँ, नया executor pass किया जा सकता है, लेकिन क्या वही वास्तव में चाहिए, इस पर संदेह है। Rust में भी कुछ ऐसा ही किया जा सकता है। colored function call की असुविधा भी वैसी ही है। कुछ core library functions के colored होने की बात Zig/Rust दोनों पर लागू नहीं होती। coloring समस्या का मूल यह है कि जिन functions को context चाहिए—यानी async executor, auth, allocator वगैरह—उन्हें call करते समय वह context देना ही पड़ता है। Zig ने सच में इस हिस्से को हल कर दिया है, ऐसा मानना मुश्किल है। हाँ, Zig की abstraction बहुत अच्छी है और Rust इस मामले में कुछ कमज़ोर पड़ता है। लेकिन function coloring की समस्या अपने आप में अब भी बनी हुई है

    • सामान्य async function coloring से मुख्य अंतर यह है कि Zig का 'Io' सिर्फ़ asynchronous processing के लिए कोई special value नहीं है, बल्कि file read, sleep, time लेना जैसी हर तरह की IO के लिए अनिवार्य value है। 'Io' function की property नहीं, बल्कि कहीं भी रखी जा सकने वाली एक सामान्य value है। व्यवहार में, इसी वजह से coloring समस्या हल होती हुई लगती है। ज़्यादातर codebase में IO पहले से किसी न किसी scope में मौजूद रहता है, इसलिए सचमुच केवल pure computation functions को ही IO की ज़रूरत नहीं पड़ती। अगर किसी function को अचानक IO की ज़रूरत पड़ जाए, तो ज़्यादातर मामलों में वह सीधे 'my_thing.io' से लेकर इस्तेमाल कर सकता है। Rust की तरह हर function में Allocator pass करने की झंझट नहीं होती। यानी code path बदलकर IO करना पड़े, तो हर function में बदलाव फैलाने की ज़रूरत नहीं, सीधे इस्तेमाल किया जा सकता है। सैद्धांतिक रूप से मैं मानता हूँ कि function coloring बची हुई है, लेकिन practically देखें तो मानो सभी functions async-colored हो गए हों, इसलिए वास्तविक समस्या लगभग नहीं रहती। असल में Zig developers यह मानते हैं कि Allocator को explicitly pass करना function coloring वाली असुविधा पैदा नहीं करता। 'Io' के साथ भी शायद यही बात होगी

    • लगता है एक महत्वपूर्ण बिंदु छूट गया। Rust library इस्तेमाल करते समय आपको async/await, tokio, send+sync जैसी शर्तें पूरी करनी ही पड़ती हैं, और अगर API sync हो तो async app में वह लगभग बेकार हो जाती है। दूसरी ओर, Zig का IO passing तरीका इस समस्या को बुनियादी रूप से हल करता है। इससे procedural macro या multi-versioning को मेहनत करके जबरन लागू करने की ज़रूरत नहीं पड़ती, और सच कहें तो यह तरीका library multi-versioning की समस्या को भी खास अच्छी तरह हल नहीं करता। Rust में async/sync mixing की समस्या पर काफ़ी चर्चा हुई है, जिसकी व्याख्या यहाँ भी है https://nullderef.com/blog/rust-async-sync/. उम्मीद है आगे चलकर Zig cooperative scheduling, high-performance async, और thread-per-core async जैसी चीज़ों को भी अच्छे से सुलझा लेगा

    • मैं category theory का विशेषज्ञ नहीं हूँ, लेकिन अंततः context management के इस रास्ते पर चलते-चलते IO monad तक पहुँचना ही पड़ता है। यह context implicit भी हो सकता है, लेकिन compiler की मदद सही तरह से चाहिए तो इसे system में किसी ठोस रूप में सामने लाना पड़ता है। और system programming languages की बड़ी महत्वाकांक्षाएँ अक्सर Async या coroutine की कब्र में दफ़न होती रही हैं, लेकिन Andrew ने किसी हद तक IO monad को फिर से खोजकर उसे ठीक से लागू किया है—यह इस पीढ़ी के लिए उम्मीद जैसी बात है। वास्तविक दुनिया के functions के रंग होते हैं। या तो उनके लिए स्पष्ट movement rules हों, या फिर C++ के co_await, tokio जैसी बढ़ती जटिलता की राह पर जाना पड़ता है। मुझे लगता है यही ‘The Way’ है

    • हर function को लाल (या नीला) बनाने की एक आसान तरकीब है

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

      अगर io को global variable बनाकर इस्तेमाल करें तो coloring की चिंता ही नहीं रहेगी। मज़ाक कर रहा हूँ, लेकिन यह सही है कि 'Io' interface इस्तेमाल करना पड़ता है, इसलिए थोड़ी friction तो है। फिर भी यह async/await इस्तेमाल करने पर होने वाली वास्तविक friction से मूल रूप से अलग समस्या है। मेरी नज़र में function coloring का असली मुद्दा यह है कि async keyword की static coloring code reuse को असंभव बना देती है। Zig में आप किसी function को async बनाएं या न बनाएं, दोनों ही हाल में वह IO को argument के रूप में लेता है, इसलिए उस दृष्टि से coloring का मतलब ही खत्म हो जाता है। दूसरी बात, async/await इस्तेमाल करने पर आपको stackless coroutine—यानी compiler-controlled stack switching—को मजबूरी में अपनाना पड़ता है, जबकि Zig का नया IO system भीतर से async इस्तेमाल करके भी Blocking IO की तरह काम कर सकता है। मुझे यही वास्तविक function coloring समस्या लगती है

    • Go में भी “सूक्ष्म coloring” की समस्या है। goroutine इस्तेमाल करते समय cancellation संभालने के लिए हमेशा context argument pass करना पड़ता है, और बहुत सी library functions भी context मांगती हैं, इसलिए पूरा codebase प्रभावित हो जाता है। तकनीकी रूप से context का उपयोग न भी करें तो चल सकता है, लेकिन context.Background को यूँ ही random तरीके से pass करना recommended तरीका नहीं है

  • sans-io की अवधारणा पर Rust आदि में पहले भी चर्चा हुई है, संदर्भ के लिए ये लिंक हैं: https://www.firezone.dev/blog/sans-io, https://sans-io.readthedocs.io/, https://news.ycombinator.com/item?id=40872020

    • अगर function सीधे IO methods को call करता है, तो बाहर से IO को अलग नहीं किया जा सकता, इसलिए उसे sans-io कहना मुश्किल है। जैसा लिंक में बताया गया है, byte stream आधारित protocol में implementation को सिर्फ़ input/output buffers से deal करना चाहिए, और network से data लेने का हिस्सा caller को खुद pass करना चाहिए—तभी वह सच में sans-io कहलाएगा। output भी या तो केवल buffer में लिखा जा सकता है, या event होने पर byte stream तुरंत return किया जा सकता है। return style implementation choice है, लेकिन internal buffer automatic response वाली situations में उपयोगी होता है। मूल बात यही है कि structure सीधे IO न करे
  • मुझे लगता है function coloring की समस्या यह है कि चाहे stack पर काम हो या stack unwind किया जाए, अंत में दोनों में से कोई न कोई चीज़ बची ही रहती है। Zig दावा करता है कि उसने coloring समस्या हल कर दी, लेकिन IO implementation के रूप में अब भी blocking/thread pool/green thread का उपयोग करने देता है। पर blocking IO तो शुरू से समस्या थी ही नहीं। global state न इस्तेमाल करने की convention मानें तो लगभग हर language में इतना तो किया ही जा सकता है। stackless coroutine अभी लागू नहीं हुआ है, इसलिए अभी यह “बाकी हिस्से खींच दो तो चित्र पूरा हो जाएगा” जैसा लगता है। अगर सच में universal function call चाहिए, तो मेरे हिसाब से दो रास्ते हैं

    • सभी functions को async बना दो, और एक argument से तय करो कि उन्हें synchronously चलाना है या नहीं (इसमें performance hit है)

    • हर function को दो बार compile करो और स्थिति के अनुसार call करो (इसमें code size बढ़ती है और function pointers संभालना कठिन होता है)

      • मैं core team में नहीं हूँ, लेकिन सुना है कि users और real-world users semiblocking implementation को पर्याप्त रूप से आज़माने के बाद, API stabilize करके ठीक उसी समाधान—stack jumping आधारित असली coroutine insertion—को लागू करने की योजना है। अभी LLVM का coroutine state-machine compiler libc या malloc पर निर्भर होने की समस्या रखता है। Zig का नया io interface userland async/await को support करता है, इसलिए आगे चलकर सही frame jumping solution आने पर migration आसान होगा और debugging भी सुविधाजनक रहेगी। अगर coroutine कठिन साबित हो, तो io API को हल्के बदलावों के साथ टिकाए रखा जा सके, ऐसा भी सोचा गया है, इसलिए stackless coroutine को लेकर बहुत जल्दबाज़ी नहीं की जा रही

      • C#/.NET का ValueTask<T> भी कुछ ऐसा ही रोल निभाता है। अगर काम synchronously पूरा हो जाए तो overhead नहीं होता, और ज़रूरत पड़ने पर ही Task<T> की तरह इस्तेमाल किया जाता है। code में आम तौर पर सिर्फ़ await लिखना होता है, और runtime या compiler execution के समय खुद तय कर लेते हैं कि sync/async में क्या चुनना है

  • मुझे Zig पसंद है, लेकिन इसे green thread (fiber, stackful coroutine) पर केंद्रित देखते हुए थोड़ा अफ़सोस होता है। Rust ने भी 1.0 से पहले ऐसा Runtime trait performance कारणों से हटा दिया था। सच तो यह है कि OS, language और libraries इस approach के दुष्प्रभाव कई बार सीख चुके हैं, और इस पर सामग्री भी है https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1364r0.pdf. 90 के दशक में fibers को scalable concurrency processing के लिए सराहा जाता था, लेकिन आज stackless coroutine, OS/hardware की प्रगति आदि के कारण उन्हें recommended नहीं माना जाता। अगर Zig इसी राह पर चलता रहा, तो उसकी performance Go जैसी सीमाओं में फँस सकती है और वह वास्तविक performance contender बनना मुश्किल पाएगा। उम्मीद है std.fs performance-sensitive cases में बना रहेगा

    • यह धारणा कि हम green thread (fiber) पर ‘all-in’ जा रहे हैं, गलतफ़हमी है। OP के संदर्भ लेख में स्पष्ट रूप से कहा गया है कि stackless coroutine आधारित implementation की उम्मीद है, और इस पर proposal भी मौजूद है https://github.com/ziglang/zig/issues/23446. performance महत्वपूर्ण है, और अगर fibers performance के लिहाज़ से उम्मीद से कम निकले, तो वे सामान्य रूप से इस्तेमाल नहीं होंगे। इस लेख में हुई चर्चा stackless coroutine को default 'Io' implementation बनने से नहीं रोकती

    • मुझे इस दावे पर संदेह है कि green thread की performance खराब होती है। कई top concurrency server platforms—Go, Erlang, Java—green thread का इस्तेमाल करते हैं या करने की कोशिश करते हैं। C FFI compatibility की वजह से low-level languages (जैसे Rust) में green thread उपयुक्त न हों, यह अलग बात है, लेकिन सिर्फ़ performance के आधार पर उन्हें खारिज करना ठीक नहीं लगता

    • क्योंकि यह कई विकल्पों में से सिर्फ़ एक है, इसलिए इसे ‘all-in’ नहीं कहा जा सकता। कौन-सा implementation चुनना है, यह executable में तय होता है, library code में नहीं

    • Zig कुछ-कुछ वही हासिल करना चाहता है जो Rust ने green thread हटाकर async runtime से किया। यहाँ मूल intuition यह है कि ‘async=IO, IO=async’। Rust tokio जैसे pluggable async runtime देता है, जबकि Zig pluggable IO runtime की दिशा में है। अंततः दिशा यही है कि runtime को language से बाहर निकाला जाए, user space में plug किया जाए, और सब एक common interface साझा करें

    • वह paper (P1364R0) विवादास्पद था, और मुझे लगता है कि वह किसी खास approach को हटाने की मंशा से प्रेरित तर्क था। चर्चा के लिए ये सामग्री भी देखी जा सकती है 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 जैसी system language में सामान्य standard IO operations तक के लिए runtime polymorphism को मजबूर करना थोड़ा अजीब लगता है। अधिकतर वास्तविक उपयोग में IO implementation statically तय की जा सकती है, तो फिर runtime overhead क्यों थोपा जाए?

    • मेरा मानना है कि IO में dynamic dispatch overhead व्यवहार में लगभग नगण्य होगा। IO target पर निर्भर करेगा, लेकिन अंततः ज़्यादातर मामलों में IO CPU bottleneck नहीं होता। इसी वजह से इसे IO-bound भी कहा जाता है

    • “सब पर runtime overhead क्यों थोपा जाए?” इस सवाल पर, मेरा अनुमान है कि जिन systems में अधिकतर सिर्फ़ एक ही तरह का io इस्तेमाल होता है, वहाँ compiler double indirection की लागत को optimize करके हटाने की कोशिश करेगा। और वैसे भी IO में bottleneck कहीं और होता है, इसलिए एक extra indirection का असर लगभग नहीं के बराबर होगा

    • Zig की philosophy binary size पर ज़्यादा ध्यान देने की है। Allocator में भी यही trade-off है; उदाहरण के लिए ArrayListUnmanaged allocator के लिए generic नहीं है, इसलिए हर allocation पर dynamic dispatch होता है। व्यवहार में file allocation या write की लागत indirect call overhead से बहुत ज़्यादा होती है। binary size के प्रति यह झुकाव Zig शैली का हिस्सा है। वैसे devirtualization—यानी dynamic call को static में बदलने वाला optimization—एक मिथक है

    • runtime polymorphism अपने आप में बुरी चीज़ नहीं है। जब तक tight loop में branch न पैदा हो, या compiler inline optimization न कर पाए, तब तक यह कोई समस्या नहीं है

  • नया io parameter जगह-जगह दिखना मुझे बहुत पसंद नहीं आया, लेकिन अलग-अलग implementations (thread आधारित, fiber आधारित आदि) को आसानी से इस्तेमाल कर पाना और user पर implementation न थोपना (Allocator interface की तरह) मुझे बहुत अच्छा लगा। कुल मिलाकर यह बड़ा सुधार है, और अगर कई stdlib implementations में अलग से overhead-रहित synchronous/blocking io implementation भी मिले, तो यह Zig की “जिसका उपयोग नहीं किया, उसकी कीमत मत दो” philosophy के बिल्कुल अनुरूप होगा

    • क्या “जिसका उपयोग नहीं किया, उसकी कीमत मत दो” वास्तव में संभव है? जब तक टीम बहुत छोटी और बेहद अनुशासित न हो, अंततः कोई और उसका उपयोग करेगा और उसकी लागत मुझे भी चुकानी पड़ेगी। और io को लगातार pass करना, ज़रूरत पड़ने पर सीधे call करने की तुलना में ज़्यादा झंझट जैसा लगता है
  • Zig में io.async सिर्फ़ asynchrony को व्यक्त करता है—यानी कामों का क्रम निश्चित न भी हो, लेकिन परिणाम सही रहेगा—यह concurrency को व्यक्त नहीं करता। यानी async और io call के अर्थ को अलग कर दिया गया है, यही इस design की असली चतुराई है

  • मुझे यह भी पसंद है कि IO interface की वजह से language स्तर का vfs (Virtual File System) बनाया जा सकता है

    • example code देखकर लगा कि security दृष्टि से capability-based security भी लागू की जा सकती है। उदाहरण के लिए किसी library को ऐसा io instance दिया जाए जो सिर्फ़ किसी खास directory के अंदर पढ़ सके। संदर्भ https://news.ycombinator.com/item?id=44549430
  • Zig सीखने के लिए मैंने एक simple ssh server बनाया था। इस बार की IO/event loop संरचना की वजह से code flow को समझना काफ़ी आसान लगा। Andy का धन्यवाद

    • मैं जानना चाहूँगा कि नए design में event loop/io को समझना आसान किस चीज़ की वजह से हुआ
  • लेख बहुत अच्छा लिखा गया है, और मैंने इसे बड़ी रुचि से पढ़ा। खास तौर पर WebAssembly के लिए इसके निहितार्थ रोमांचक लगते हैं। userspace में WASI इस्तेमाल करना, और Bring Your Own IO जैसी संरचना—यह सच में बहुत दिलचस्प है