5 पॉइंट द्वारा GN⁺ 2025-07-20 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Asynchrony और concurrency ऐसे कॉन्सेप्ट हैं जिन्हें अक्सर गड़बड़ कर दिया जाता है, लेकिन इनके अर्थ अलग हैं
  • Asynchrony का मतलब है कि काम क्रम की परवाह किए बिना चल सकें
  • Concurrency का मतलब है कि सिस्टम कई कामों को एक साथ आगे बढ़ा सके
  • भाषा और लाइब्रेरी ecosystem में इन दोनों के बीच स्पष्ट फर्क न होने से अप्रभावशीलता और जटिलता पैदा होती है
  • Zig भाषा में asynchrony और concurrency को अलग करके synchronous और asynchronous code को बिना code duplication के साथ रहने देना संभव है

परिचय: asynchrony और concurrency में फर्क क्यों ज़रूरी है

Rob Pike की मशहूर बात 'concurrency is not parallelism' काफी जानी-पहचानी है, लेकिन इससे भी ज्यादा व्यावहारिक एक और अहम बिंदु है। वह है 'asynchrony' की ज़रूरत। Wikipedia की परिभाषा के अनुसार,

  • Concurrency: किसी सिस्टम की यह क्षमता कि वह कई कामों को time-slicing या parallel तरीके से एक साथ संभाल सके
  • Parallel computing: वास्तविक भौतिक स्तर पर कई कामों का एक साथ चलना
    इनके अलावा, एक और महत्वपूर्ण कॉन्सेप्ट है जिसे हम अक्सर नज़रअंदाज़ कर देते हैं: 'asynchrony'.

उदाहरण 1: दो फ़ाइल सेव करना

अगर दो फ़ाइलों (A, B) को सेव करते समय क्रम मायने नहीं रखता, तो

io.async(saveFileA, .{io})
io.async(saveFileB, .{io})
  • पहले A सेव हो या B, कोई फर्क नहीं पड़ता
  • बीच-बीच में बारी-बारी से सेव हो, तब भी कोई समस्या नहीं
  • यहाँ तक कि A पूरी तरह सेव होने के बाद B शुरू हो, तब भी code के हिसाब से यह सही है

उदाहरण 2: दो socket (server, client)

जब एक ही प्रोग्राम में TCP server बनाना हो और client को connect कराना हो,

io.async(Server.accept, .{server, io})
io.async(Client.connect, .{client, io})
  • इस स्थिति में दोनों कामों का ओवरलैप होकर चलना ज़रूरी है
  • यानी जब server connection accept कर रहा हो, उसी दौरान client को भी connect की कोशिश करनी चाहिए
  • अगर पहले फ़ाइल वाले उदाहरण की तरह इसे serial तरीके से चलाया जाए, तो इच्छित व्यवहार नहीं मिलेगा

कॉन्सेप्ट की परिभाषा

asynchrony, concurrency, और parallelism को इस तरह परिभाषित किया जा सकता है

  • Asynchrony: वह गुण जिसमें काम क्रम से हटकर चलें तब भी सही परिणाम मिले
  • Concurrency: कई कामों को, चाहे parallel हो या sliced execution में, एक साथ आगे बढ़ाने की क्षमता
  • Parallelism: कई कामों का भौतिक रूप से real time में एक साथ चलना

फ़ाइल सेव करने और socket connect करने वाले दोनों उदाहरण asynchronous हैं, लेकिन दूसरे वाले (server-client) में concurrency अनिवार्य है

asynchrony और concurrency को अलग समझने का फायदा

अगर यह फर्क न किया जाए, तो कई समस्याएँ पैदा होती हैं

  • लाइब्रेरी बनाने वालों को asynchronous और synchronous version का code दो बार लिखना पड़ता है (जैसे: redis-py vs asyncio-redis)
  • user के लिए async code 'संक्रामक' बन जाता है, यानी सिर्फ एक asynchronous library dependency होने पर भी पूरे project को async बनाना पड़ता है
  • इससे बचने के लिए लोग workaround अपनाते हैं, जो अक्सर *deadlock* और अप्रभावशीलता पैदा करते हैं

इसलिए, इन दोनों कॉन्सेप्ट्स को स्पष्ट रूप से अलग करना लाइब्रेरी लेखकों और users दोनों के लिए बहुत फायदेमंद है

Zig: asynchrony और concurrency का अलगाव

Zig भाषा io.async के जरिए asynchrony का उपयोग करती है, लेकिन यह concurrency की गारंटी नहीं देती

  • यानी io.async इस्तेमाल होने पर भी अंदर से single-thread, blocking mode में execution संभव है
  • उदाहरण के लिए
    io.async(saveFileA, .{io})
    io.async(saveFileB, .{io})
    
    यह code blocking environment में
    saveFileA(io)
    saveFileB(io)
    
    के समान काम कर सकता है
  • यानी लाइब्रेरी लेखक io.async का इस्तेमाल करें, तब भी user चाहें तो इसे sequential blocking IO के रूप में चला सकता है

concurrency की शुरुआत और task switching (scheduling) mechanism

जहाँ concurrency की ज़रूरत हो, वहाँ वास्तविक और प्रभावी व्यवहार के लिए

  1. blocking के बजाय event-based IO (epoll, io_uring आदि) का उपयोग
  2. task switching primitive (जैसे: yield) की ज़रूरत
  • उदाहरण के तौर पर, Zig green-thread environment में stack swapping तकनीक से task switching करता है
  • OS स्तर की thread scheduling की तरह, CPU register और stack जैसी state को save/restore करके कई tasks के बीच switch किया जाता है
  • ऐसा switching mechanism होना जरूरी है, तभी asynchronous code को वास्तव में concurrently schedule किया जा सकता है
  • stackless coroutine implementation (जैसे: suspend, resume) भी इसी सिद्धांत पर काम करती है

synchronous code और asynchronous code का सह-अस्तित्व

अगर नीचे की तरह saveData को दो बार io.async से चलाया जाए,

io.async(saveData, .{io, "a", "b"})
io.async(saveData, .{io, "c", "d"})
  • दोनों काम एक-दूसरे से asynchronous हैं, इसलिए भले ही function अंदर से synchronous लिखा गया हो, फिर भी उन्हें स्वाभाविक रूप से concurrency context में schedule किया जा सकता है
  • user या लाइब्रेरी लेखक code duplication के बिना synchronous/asynchronous functions को साथ इस्तेमाल कर सकते हैं

जहाँ concurrency 'अनिवार्य' है, उसे स्पष्ट करना

कुछ functions (जैसे TCP server का accept) के लिए code में साफ़-साफ़ बताना ज़रूरी है कि execution के समय concurrency चाहिए

  • Zig में इसके लिए io.asyncConcurrent जैसे explicit function से फर्क दिखाया जाता है
  • ऐसा तरीका यह सुनिश्चित करता है कि अगर execution environment concurrency support नहीं करता, तो error मिले
  • asynchrony के लिए इस्तेमाल होने वाले io.async से अलग, यहाँ concurrency guarantee अनिवार्य है, इसलिए इसे failable function के रूप में लागू किया जाता है

निष्कर्ष

  • Asynchrony और concurrency पूरी तरह अलग कॉन्सेप्ट हैं, और इन्हें स्पष्ट रूप से अलग समझना चाहिए
  • synchronous code और asynchronous code का सह-अस्तित्व संभव है
  • Zig का asynchrony/concurrency model बिना code duplication के दोनों दुनिया का साथ में उपयोग करने देता है
  • ऐसी संरचना Go जैसी दूसरी भाषाओं में भी लागू हुई है, और यह async/await की संक्रामकता से आगे निकलने का रास्ता दिखाती है
  • Zig के नए async I/O design के साथ, आगे और अधिक सहज concurrency/asynchrony programming environment की उम्मीद की जा सकती है

1 टिप्पणियां

 
GN⁺ 2025-07-20
Hacker News राय
  • async को परिभाषित करना सच में बहुत मुश्किल लगता है, और मैं खुद भी JavaScript में async डिज़ाइन करने वाले कई लोगों में से एक हूँ, इसलिए इस लेख में दी गई परिभाषा से सहमत नहीं हूँ, सिर्फ async होने से चीज़ें अपने-आप सही नहीं हो जातीं, async code में भी कई तरह की user-level race condition हो सकती हैं, चाहे language async/await को support करे या नहीं, दोनों ही स्थिति में ऐसा होता है, हाल में मेरी अपनी परिभाषा यह रही है कि async वह है "ऐसा code जिसे concurrency के लिए स्पष्ट रूप से संरचित किया गया हो", हालांकि इस नज़रिए को भी अभी और परिष्कृत करने की ज़रूरत है, इस विषय पर मैंने खुद भी एक लेख लिखा है, देखें Quite a few words about async

    • मेरा मानना है कि asynchronism जैसी अमूर्त अवधारणा और उसकी वास्तविक implementation के बीच फर्क करना ज़रूरी है, बाद वाली में language-level abstraction भी आते हैं और mechanical coordination के साधन भी, सबसे ऊँचे अमूर्त स्तर पर asynchronism, synchronism का उल्टा है, आम तौर पर जब कई entities को साथ काम करना होता है, जैसे एक task पूरा होने के बाद ही दूसरा task आगे बढ़ सकता है, तब वह कब होगा यह अगर अज्ञात हो या परिभाषित न हो, तो वही async का मूल है, यह परिभाषा अपने-आप में कठिन नहीं है, कठिनाई तब आती है जब language स्तर पर इस abstraction को डिज़ाइन करना पड़ता है और उससे cognitive load बढ़ता है

    • मैं इस विषय का बहुत गहरा जानकार नहीं हूँ, लेकिन मेरी समझ में async code वह है जो मूल रूप से blocking operation को non-blocking में बदल देता है ताकि बाकी काम साथ-साथ आगे बढ़ सकें, खासकर embedded loop के मेरे अनुभव में लंबे समय तक blocking code I/O को बिगाड़ सकता है और ऐसे errors ला सकता है जो दिखते या सुनाई देते हैं, इसलिए मेरे लिए यह नज़रिया काफी स्पष्ट है

    • मुझे तो यह भी संदेह है कि async को परिभाषित करना ज़रूरी भी है या नहीं, असल में इसे परिभाषित करना इसलिए कठिन है क्योंकि कोई एक अवधारणा इस पर पूरी तरह फिट नहीं बैठती, यह भी निश्चित नहीं कि async या event loop को सख्ती से define करना ज़रूरी है, जिन physical chip areas में वास्तविक parallel processing होती है वहाँ शायद मेरी जानकारी से कहीं ज़्यादा अवधारणाएँ होंगी, लेकिन मेरे लिए “user finger” (जैसे touch input), “quickies” (बहुत कम समय लेने वाले काम), job queue, और blocking/non-blocking API समझना काफी है, अपना काम पूरा करने के लिए मुझे non-blocking API पसंद हैं, क्योंकि लंबे काम नीचे के subsystem को सौंपे जा सकते हैं और मैं सिर्फ data store जैसे “quicky” लिख सकता हूँ, साथ ही success/failure के लिए अलग quicky define कर सकता हूँ, sync और async का फर्क अपने-आप में बहुत मददगार नहीं है, हाँ, दूसरों की बात समझने के लिए इतना जानना पड़ता है, मूल रूप से मेरे लिए async मतलब non-blocking API है, और async programming model वह है जिसमें relatively छोटे और atomic blocking काम “अराजक और non-deterministic” events के हिसाब से लिखे जाते हैं, system के अंदर जो भी हो, मैं बस यह मानता हूँ कि browser, OS, या device में multi execution units और अच्छा scheduler होता है, मेरे लिए async एक धुँधला-सा term है, और अगर इसे define किया भी जा सके तो भी पता नहीं वह कितना उपयोगी होगा, बल्कि event, मेरे द्वारा लिखे जा रहे कामों का blocking nature, function closure, और API इस्तेमाल करते समय कौन-सा काम अलग job में टूटता है, ये सब ज्यादा व्यावहारिक concepts हैं, “callback” शब्द भी शुरुआत में बहुत confusing था, मुझे लगता था code वहीं रुक गया है, लेकिन असल में वह हिस्सा अंत तक execute होता है और उसके बाद “callback” कब चलेगा, उसमें कौन-सा code चलेगा, और कौन-सी information उपलब्ध होगी, यह बहुत सटीक समझना पड़ता है, सच कहूँ तो यह chaos भी है और genius भी, “async” से ज़्यादा मूल model, यानी events, blocking work, job queue, और non-blocking API कहीं सरल हैं, और यह समझना भी बहुत ज़रूरी है कि मैं क्या कर रहा हूँ और browser/OS वगैरह क्या कर रहे हैं, जैसे cpp में आप concurrent model declare करते हैं लेकिन असली execution OS संभालता है, JS में non-blocking API के ज़रिए आप browser या Node को बताते हैं कि यहाँ “शायद” concurrency है और वे अंदरूनी तौर पर उसे concurrent तरीके से संभालते हैं, सबसे महत्वपूर्ण बात यह है कि हर job को छोटा (<50ms) रखा जाए और non-blocking API के ज़रिए बस intent व्यक्त कर दिया जाए, cpp या rust में आप OS को बताते हैं कि tasks को concurrent तरीके से चलाया जाए, इसलिए physical रूप से एक ही thread होने पर भी UI responsive रह सकता है, अंततः async programmer का काम है एक “अच्छा UX model” बनाना और events को quickies से सही तरीके से map करना

  • मुझे लगता है कि लेखक ने “yield” की अवधारणा को concurrency की परिभाषा से निकालकर एक नए शब्द “asynchrony” में डाल दिया है, और फिर कहता है कि इसके बिना concurrency ही टूट जाती है, मेरी राय में concurrency में yield पहले से ही अंतर्निहित है, क्योंकि यह उसकी बुनियादी ज़रूरत है, यह महत्वपूर्ण अवधारणा तो है, लेकिन इसे अलग नए term के रूप में निकालना केवल भ्रम बढ़ाता है

    • मेरे हिसाब से 1:1 parallelism, बिना yield वाली concurrency का एक रूप है, उसके अलावा हर non-parallel concurrency में किसी-न-किसी cadence पर yield करना ही पड़ता है, चाहे instruction level पर ही क्यों न हो, उदाहरण के लिए CUDA में एक ही warp के भीतर branch हुए threads एक-दूसरे के instructions interleave करते हैं, और एक branch दूसरी को block कर सकती है

    • मैं यह रेखांकित करना चाहूँगा कि उद्धृत लेख में खुद साफ़ लिखा है कि “yield concurrency की अवधारणा है”

    • concurrency का अर्थ हमेशा yield नहीं होता, synchronous logic को स्पष्ट synchronization चाहिए, और yield तो synchronization का सिर्फ एक तरीका है, मैं जिस asynchronous logic की बात कर रहा हूँ उसका मतलब है ऐसी concurrency जो synchronization या yield के बिना चलती हो, व्यावहारिक रूप से concurrency या asynchronous logic von Neumann machine पर पूरी तरह मौजूद नहीं है

  • इस संदर्भ में async वह abstraction है जो request की तैयारी/submit करने और result इकट्ठा करने को अलग कर देती है, इससे आप कई requests submit करने के बाद ही उनके results देख सकते हैं, यह concurrent implementation को संभव बनाती है, लेकिन अनिवार्य नहीं करती, फिर भी इस abstraction का उद्देश्य concurrency पाना ही है, concurrency न हो तो इसका लाभ भी नहीं बचता, कुछ async abstractions तो न्यूनतम concurrency के बिना implement ही नहीं हो सकतीं, जैसे callback style को single-thread पर नकल करके दिखाया जा सकता है, लेकिन non-recursive mutex पकड़े होने पर deadlock जैसी सीमाएँ सामने आती हैं, यानी concurrency के बिना async abstraction अंततः विफल होगी ही, अगर requester mutex पकड़े हुए request करे और unlock होने से पहले callback चल जाए, तो unlock शायद कभी न हो, कम-से-कम अलग thread तो चाहिए ताकि requester unlock तक पहुँच सके

    • सहमत हूँ, लेख में दिया server-client example सिर्फ एक case है, और आपने जो case बताया वह बिल्कुल अलग तरह के समाधान माँगता है, आगे भी ऐसे और कई cases सामने आएँगे, नतीजा यही है कि async इस्तेमाल करते समय हमेशा concurrency सुनिश्चित करनी होगी
  • "cooperative multitasking preemptive नहीं है", और “async” शब्द का उपयोग आम तौर पर “single-thread, cooperative multitasking (explicit yield) और event-driven model” के लिए होता है, जहाँ बाहरी operations concurrently चलते हैं और अपने result events के रूप में report करते हैं, multi-threaded या concurrent execution model में async का अर्थ बहुत कम रह जाता है, क्योंकि वह particular thread block हो जाए तब भी program आगे चलता रहता है, और yield points को explicit होने की ज़रूरत नहीं रहती

    • Rust, C#, F#, OCaml(5+) आदि OS threads और async दोनों को support करते हैं, OS threads CPU-bound work के लिए अच्छे हैं, async IO-bound work के लिए, async या Go-style M:N scheduling का सबसे बड़ा लाभ यह है कि memory उपलब्ध हो तो आप tasks/goroutines को मनचाहे scale तक बढ़ा सकते हैं, OS thread model में context-switch overhead, thread/memory exhaustion जैसी समस्याएँ आती हैं, इसलिए IO-bound workload बढ़ते ही deadlock जैसी स्थिति भी बन सकती है
  • Zig का नया IO idea सामान्य app development के लिए नया और रोचक लगता है, stackless coroutine न चाहने वालों के लिए यह optimal हो सकता है, लेकिन library writing में इससे errors बढ़ सकते हैं, library author के लिए यह समझना कठिन होगा कि दिया गया IO single-threaded है या multi-threaded, event-driven IO है या कुछ और, concurrency/async/parallelism से जुड़ा code वैसे भी पूरे IO stack को जानने पर भी लिखना मुश्किल होता है, और जब IO बाहर से inject हो रहा हो तो यह कठिनाई और बढ़ जाती है, अगर IO interface एक “छोटे OS” जितना बड़ा हो जाए तो test scenarios भी विस्फोटक रूप से बढ़ जाएँगे, मुझे भरोसा नहीं कि interface में दिए गए async primitives से सभी edge cases संभाले जा सकेंगे, कई तरह की IO implementations को support करना हो तो code को बहुत defensive होना पड़ेगा और हमेशा सबसे ज्यादा parallel IO मानकर चलना होगा, खासकर stackless coroutines के साथ इस approach को मिलाना आसान नहीं होगा, बेवजह coroutine spawn कम करने हों तो coroutine की explicit polling चाहिए होगी, लेकिन ज़्यादातर developers ऐसा code खुद नहीं लिखेंगे, अंततः चीज़ें शायद साधारण async/await code जैसी ही बन जाएँगी, dynamic dispatch और Zig की bottom-up design tendency को देखें तो यह अंत में काफी high-level language जैसी लगने लगेगी, अभी तक इसकी वास्तविक usage examples नहीं हैं, इसलिए इसे “compromise-free” कहना अभी कुछ ज्यादा ही साहसी लगता है, असली मूल्यांकन तो कुछ साल उपयोग के बाद ही हो सकेगा

    • stackless coroutines तो वैसे भी planned हैं, क्योंकि WASM target support के लिए उनकी ज़रूरत पड़ेगी, dynamic dispatch सिर्फ तब इस्तेमाल होगा जब दो या उससे ज्यादा IO implementations हों, एक ही implementation हो तो वह direct call से replace हो जाएगा, और चूँकि यह अभी production में साबित नहीं हुआ है, इसलिए “compromise-free” कहना मुझे भी समय से पहले लगता है, मैंने सुना है कि Jai language में इससे मिलता-जुलता model सफलतापूर्वक इस्तेमाल होता है, हालाँकि वहाँ explicit context passing के बजाय implicit IO context है, लेकिन उसे भी अभी वास्तविक field use कहना मुश्किल है

    • मैं इस बात से सहमत हूँ कि synchronous और asynchronous execution दोनों को support करना हो तो code को हमेशा सबसे अधिक parallel IO की संभावना मानकर लिखना पड़ेगा, लेकिन अगर low-level IO event handlers में async सही तरीके से implement किया गया हो, तो फिर हर जगह वही सिद्धांत लागू करना होगा, सबसे खराब स्थिति में code सिर्फ sequentially, यानी धीमे चलेगा, लेकिन race/deadlock जैसी समस्याओं में नहीं फँसेगा

  • मुझे Zig का यह विचार बहुत अच्छा लगता है कि दो अलग libraries रखने की ज़रूरत नहीं पड़ेगी, लेकिन async code की testing को लेकर हमेशा चिंता रहती है, आज जो test pass हुआ है वह क्या सच में runtime में होने वाले हर scenario/order को reproduce करता है, यह कैसे पता चले, threads वाले program में भी यही समस्या होती है, लेकिन multi-threaded code लिखना और debug करना हमेशा ज़्यादा कठिन रहा है, मैं तो संभव हो तो threads से बचता हूँ, असली समस्या है ‘developer को async/threaded environment ठीक से समझाना’, हाल में मैंने एक टीम के साथ काम किया जिसने Python system में आधा JS और आधा Python लिखा था, और फिर बड़े codebase को async और threaded बना दिया, लेकिन उन्हें Global Interpreter Lock (GIL) क्या है यह भी नहीं पता था, शायद मेरी बातें उन्हें सिर्फ बेमतलब की नसीहत लगीं, ऊपर से उनके tests तो code तोड़ देने पर भी pass हो जाते थे, mangum HTTP request खत्म होने पर background और async tasks को ज़बरदस्ती finish करवा देता है, और उन्हें यह भी नहीं पता था, और ऐसी बातें बताने पर भी लोग अक्सर उदासीन रहते हैं, सिर्फ आपका जानना काफी नहीं, ज़रूरी यह है कि दूसरे लोग उस पर ध्यान देते हैं या नहीं

    • Zig में Io के लिए test implementation लाने की योजना है, जिससे parallel execution model के तहत fuzz testing जैसी stress testing भी की जा सकेगी, लेकिन मुख्य बात यह है कि अधिकांश library code को शायद io.async या io.asyncConcurrent सीधे call करने की ज़रूरत ही नहीं होगी, उदाहरण के लिए ज़्यादातर database libraries पूरी तरह synchronous code से काम चला सकती हैं, application developer बाद में उस code को io.async(writeToDb), io.async(doOtherThing) की तरह आसानी से async बना सकता है, इससे async/await को पूरे codebase में छिड़कने की तुलना में errors कम होंगे और समझना भी आसान होगा

    • पूरी तरह सहमत, async और multi-threaded code में हर possible interleaving को test करना बदनाम रूप से कठिन है, fuzzer या concurrency testing framework इस्तेमाल करने पर भी production से मिले सबक के बिना भरोसा करना मुश्किल है, distributed systems में तो यह और भी खराब हो जाता है, जैसे webhook infrastructure डिज़ाइन करते समय सिर्फ अपने code के अंदर का async ही नहीं, बल्कि network retries, timeouts, partial failures जैसी बाहरी समस्याएँ भी जुड़ जाती हैं, high-concurrency environment में retry, deduplication, idempotency guarantee जैसी engineering चुनौतियाँ खुद अलग समस्या बन जाती हैं, इसलिए Vartiq.com जैसी specialized services की ज़रूरत पड़ती है (मैं वहीं काम करता हूँ), ऐसे services operational concurrency complexity का कुछ हिस्सा abstract करके blast radius कम कर देते हैं, लेकिन मेरे अपने code के async testing issues फिर भी बने रहते हैं, कुल मिलाकर async, threading, और distributed concurrency एक-दूसरे के risk को बढ़ाते हैं, इसलिए communication और system design किसी भी syntax या library से ज़्यादा महत्वपूर्ण हैं

  • मुझे लगता है कि लेखक concurrency की definition को लेकर भ्रमित है, Lamport का paper देखना उपयोगी होगा

    • सिर्फ paper link छोड़ने के बजाय थोड़ा समझा भी दीजिए, मेरी नज़र में definition बुरी नहीं थी, जैसे asynchronous: अगर operations को क्रम में execute होना ज़रूरी न हो और फिर भी सब सही रहे, तो वह asynchronous है, concurrency: system की वह property जिसमें कई काम parallelism या task switching के ज़रिए साथ आगे बढ़ सकते हैं, parallelism: जहाँ physical स्तर पर सचमुच दो या ज़्यादा काम एक साथ चल रहे हों

    • इसी वजह से मैंने इन terms का इस्तेमाल लगभग पूरी तरह छोड़ दिया है, आप किसी से भी बात करें, हर किसी की समझ अलग निकलती है, इसलिए शब्द खुद संचार के लिए बेअर्थ हो जाते हैं

    • लेखक को भी अपने blog post में यह पता है कि इस term की पहले से definitions मौजूद थीं, वह बस अपनी एक नई definition propose कर रहा है, और अगर वह definition खुद के भीतर consistent है, तो इतना काफी है, फर्क सिर्फ इतना है कि पाठक उसे स्वीकार करते हैं या नहीं

    • Lamport के paper का आधा हिस्सा ज़्यादातर languages में conceptual रूप से व्यक्त ही नहीं किया जा सकता, सिर्फ thread बना लेने से total order और partial order पर चर्चा करने की ज़रूरत शायद ही पड़ती है, ऐसी बातों की ज़रूरत TLA+ में protocol design करते समय आती है, Zig async API में अगर कोई function “सिर्फ asynchronous execution environment में काम करता है” और नहीं तो compile error देता है, तो उसे कोई नई theory कहने की ज़रूरत नहीं

  • यह परखने का अच्छा तरीका कि “asynchrony” शब्द की वाकई ज़रूरत है या नहीं, यह देखना है कि क्या यह सिर्फ एक language/model में नहीं बल्कि कई concurrency models में भी उपयोगी साबित होता है, जैसे Haskell, Erlang, OCaml, Scheme, Rust, Go वगैरह में, आम तौर पर जब cooperative scheduling आती है तो पूरे system को एक code path की समस्या से lockup या latency जैसी परेशानियों का ज़्यादा खतरा होता है, जबकि preemptive scheduling में ऐसे बहुत-से issues काफी हद तक गायब हो जाते हैं, क्योंकि पूरे system का lockup होना लगभग असंभव हो जाता है, और समस्या-क्षेत्र बहुत छोटा रह जाता है

  • इस मामले में “asynchrony” सही शब्द नहीं है, जबकि “commutativity” जैसा पहले से अच्छी तरह परिभाषित गणितीय शब्द मौजूद है, कुछ operations में order मायने नहीं रखता, जैसे addition या multiplication, जबकि कुछ में order बहुत मायने रखता है, जैसे subtraction या division, सामान्य code में operations का क्रम line numbers यानी ऊपर-से-नीचे के हिसाब से व्यक्त होता है, लेकिन async code में यह क्रम टूट जाता है, इसलिए asyncConcurrent(...) जैसी चीज़ स्वाभाविक रूप से confusing लगती है, अगर आपने blog post को पूरी तरह internalize नहीं किया है तो उसका अर्थ पकड़ना कठिन है, Zig में, और सच कहूँ तो मेरी पसंदीदा Rust में भी, इस तरह के थोड़े “hipster” approaches अक्सर दिखते हैं, बेहतर होगा कि procedural async-based commutativity/order system को Rust lifetimes जैसी किसी चीज़ की तरह implement किया जाए, या फिर लोग जिस चीज़ के पहले से अभ्यस्त हैं वही इस्तेमाल की जाए

    • मैं “asyncConcurrent(...) confusing है” वाली बात से सहमत नहीं हूँ, अगर आप blog post के मुख्य विचार को आत्मसात कर लें तो यह बिल्कुल भी confusing नहीं है, हाँ, वह विचार सीखने लायक है या नहीं यह अलग सवाल है, अगर बहुत लोग इसे सीखकर व्यवहार में आज़माएँ, तो समय के साथ पता चल जाएगा कि field में यह idea अच्छा है या नहीं, और “commutativity” शब्द को विकल्प के रूप में लाने से Zig में उल्टा और confusion हो सकता है, क्योंकि वहाँ operators सच में commutative हो सकते हैं, तो लोग पूछेंगे कि अगर f() + g() में addition commutative है तो क्या Zig उसे parallel में चला सकता है, जबकि execution order और commutativity पूरी तरह अलग बातें हैं, इसलिए उन्हें अलग रखना चाहिए

    • तकनीकी रूप से commutativity (द्विआधारी) operations की property है, जब हम कहते हैं कि दो async statements जैसे connect/accept एक-दूसरे से commute करते हैं, तो सवाल आता है “किस operation के सापेक्ष?”, फिलहाल bind (>>=) operator या .then(...) जैसी चीज़ शायद इसके सबसे करीब आती है, लेकिन यह अभी भी अधिकतर intuition का मामला है

    • asynchronous execution partial order की भी अनुमति देता है, दो operations को result retirement के स्तर पर एक ही क्रम में पूरा होना पड़ सकता है, भले ही actual execution order कुछ और हो, जैसे subtraction commutative नहीं है, लेकिन balance calculation और deduction calculation को दो queries में parallel चलाकर, फिर result को सही क्रम में apply करना संभव है

    • सिर्फ इसलिए कि कोई दूसरा term इस अवधारणा को समाहित कर सकता है, यह नहीं मान लेना चाहिए कि वह “asynchrony” से बेहतर शब्द है, “commutativity” पढ़ने, सुनने और लिखने में कहीं ज़्यादा बोझिल है, asynchrony अधिक परिचित शब्द है

    • commutativity वाली बात की अपनी सीमा है, अगर A और B दोनों, C के साथ commute करते हैं, तो ABC = CAB हो सकता है, लेकिन इससे यह ज़रूरी नहीं कि ACB भी समान हो, जबकि async में ABC = ACB = CAB सब समान होना चाहिए, अगर इसके लिए कोई स्थापित गणितीय शब्द है तो मुझे नहीं पता

  • network programmer के तौर पर मैंने concurrency, parallelism, और async code बहुत लिखा है, लेकिन यह लेख मुझे कुछ उलझा हुआ लगता है, जैसे किसी कमजोर abstraction पर टिककर जवाब खोजने की कोशिश की जा रही हो, अगर tools या implementation ही गलत हों तो उनका इतनी आसानी से “टूट” जाना ही समस्या है, वैसे multi-threaded code debug करना अपने-आप में काफी मज़ेदार भी होता है, इसलिए जब दूसरे लोग multi-threaded monsters से बहुत डरते हैं तो मुझे उल्टा अच्छा लगता है