2013-06-27 5 views
10

मुझे file system library में बहुत सारे सिंक्रोनस फ़ंक्शन दिखाई देते हैं। जैसे fs.readFileSync(filename, [options])यदि नोडज गैर ब्लॉकिंग आईओ का उपयोग करता है, तो fs.readFileSync कैसे कार्यान्वित किया जाता है?

इन कार्यों को कैसे कार्यान्वित किया जाता है यदि नोड में एसिंक/गैर-अवरुद्ध आईओ और कोई नींद विधि नहीं है - और क्या मैं अन्य तुल्यकालिक कार्यों को लागू करने के लिए एक ही तंत्र का उपयोग कर सकता हूं?

+0

अच्छा सवाल! शायद किसी को जावास्क्रिप्ट के लिए कोरआउट को फिर से शुरू करने और घटना लूप का पर्दाफाश करने की आवश्यकता होगी ताकि node.js में सिंक्रोनस गैर अवरोधन कोड लिखने की अनुमति मिल सके। – Alex

उत्तर

15
fs.readFileSync() 

वास्तव में सिर्फ

fs.readSync() 

समारोह के लिए एक आवरण है। तो सवाल यह है कि fs.readSync() fs.read() की तुलना में कार्यान्वित किया गया है। यदि आप इन दो कार्यों के कार्यान्वयन को देखते हैं तो वे दोनों बाइंडिंग मॉड्यूल का लाभ उठाते हैं। इस मामले में कौन सा

var binding = process.binding('fs'). 

को intialized जाता है और कॉल क्रमशः

binding.read(fd, buffer, offset, length, position, wrapper);//async 
var r = binding.read(fd, buffer, offset, length, position);//sync 

हैं। एक बार जब हम "बाध्यकारी" मॉड्यूल में हों, तो हम v8, node _ ##### सीसी भूमि में बाहर हैं। बाध्यकारी ('एफएस') का कार्यान्वयन नोड_फाइल.सीसी में, नोड भंडार कोड में पाया जा सकता है। नोड इंजन सी ++ कॉल के लिए अधिभार प्रदान करता है, एक कॉलबैक लेता है, जो ऐसा नहीं करता है। Node_file.cc कोड req_wrap वर्ग का लाभ लेता है। यह v8 इंजन के लिए एक रैपर है।

#define ASYNC_CALL(func, callback, ...)       \ 
    FSReqWrap* req_wrap = new FSReqWrap(#func);      \ 
    int r = uv_fs_##func(uv_default_loop(), &req_wrap->req_,  \ 
     __VA_ARGS__, After);          \ 
    req_wrap->object_->Set(oncomplete_sym, callback);    \ 
    req_wrap->Dispatched();           \ 
    if (r < 0) {             \ 
    uv_fs_t* req = &req_wrap->req_;        \ 
    req->result = r;            \ 
    req->path = NULL;            \ 
    req->errorno = uv_last_error(uv_default_loop()).code;   \ 
    After(req);             \ 
    }                \ 
    return scope.Close(req_wrap->object_); 

#define SYNC_CALL(func, path, ...)        \ 
    fs_req_wrap req_wrap;           \ 
    int result = uv_fs_##func(uv_default_loop(), &req_wrap.req, __VA_ARGS__, NULL); \ 
    if (result < 0) {            \ 
    int code = uv_last_error(uv_default_loop()).code;    \ 
    return ThrowException(UVException(code, #func, "", path)); \ 
    } 

सूचना है कि SYNC_CALL एक अलग अनुरोध-चादर का उपयोग करता है: node_file.cc में हम इस को देखते हैं। यहाँ ASYNC विधि के लिए प्रासंगिक req_wrap निर्माता के लिए कोड है, req_wrap.h में

ReqWrap() { 
    v8::HandleScope scope; 
    object_ = v8::Persistent<v8::Object>::New(v8::Object::New()); 

    v8::Local<v8::Value> domain = v8::Context::GetCurrent() 
            ->Global() 
            ->Get(process_symbol) 
            ->ToObject() 
            ->Get(domain_symbol); 

    if (!domain->IsUndefined()) { 
     // fprintf(stderr, "setting domain on ReqWrap\n"); 
     object_->Set(domain_symbol, domain); 
    } 

    ngx_queue_insert_tail(&req_wrap_queue, &req_wrap_queue_); 
    } 

सूचना है कि इस समारोह के लिए एक नया v8 गुंजाइश वस्तु पैदा कर रही है इस घटना के चल रहा है संभाल करने के लिए मिल गया। यह वह जगह है जहां एसिंक सामग्री का असीमित हिस्सा होता है। V8 इंजन ने इस विशेष कॉल को अलग से संभालने के लिए एक नया जावास्क्रिप्ट व्याख्यान वातावरण लॉन्च किया है। संक्षेप में, नोड के अपने संस्करण को बनाने/संशोधित किए बिना, आप अपने स्वयं के एसिंक्रोनस/कॉल के सिंक्रोनस संस्करणों को लागू नहीं कर सकते हैं, वैसे ही नोड करता है। ऐसा कहा जा रहा है कि, असीमित वास्तव में केवल I/O संचालन पर लागू होता है। शायद आपको लगता है कि आपको क्यों लगता है कि आपको चीजों को और अधिक तुल्यकालिक होने की आवश्यकता है। आम तौर पर, अगर आपको लगता है कि नोड कुछ ऐसा करने का समर्थन नहीं करता है जिसे आप करना चाहते हैं, तो आप कॉलबैक तंत्र को पूरी क्षमता में स्वीकार नहीं कर रहे हैं।

कहा जा रहा है कि यदि आप एसिंक व्यवहार की आवश्यकता है तो आप अपने स्वयं के ईवेंट हैंडलर को लागू करने के लिए ईवेंट नोड मॉड्यूल का उपयोग करने पर विचार कर सकते हैं। और यदि आप ऐसी चीजें हैं जो आपको सिंक्रनाइज़ करने की जरुरत है, तो आप देशी एक्सटेंशन पर विचार कर सकते हैं, हालांकि, मैं इसके खिलाफ अत्यधिक अनुशंसा करता हूं। इस तरह से करने के लिए आपको क्या करने की आवश्यकता है, इस पर विचार करें कि आप एसिंक्रोनस इवेंट लूप के भीतर कैसे काम कर सकते हैं। सोच की इस शैली को गले लगाओ, या दूसरी भाषा में स्विच करें।

चीजों को संभालने के लिए एक भाषा को मजबूर करना जिस तरह से उन्हें संभालना नहीं है, वह खराब कोड लिखने का एक शानदार तरीका है।

+1

बहुत गहन जवाब। 'ऐसी चीजों को संभालने के लिए एक भाषा को मजबूर करना जिससे वह उन्हें संभालना नहीं चाहता' - एक दिलचस्प वाक्यांश है। क्या यह ठीक नहीं है कि नोडजेएस लोग 'fs.readFileSync' के साथ क्या कर रहे हैं? यह बिल्कुल क्यों मौजूद है? हो सकता है कि नोड में सिंक्रोनस कॉल के लिए सब कुछ हो? –

+0

स्टैकओवरफ्लो ... कभी नहीं पता कि आप किसी ऐसे उपकरण को कब सौंप रहे हैं जो वे उपयोग करने के लिए तैयार नहीं हैं।वह आखिरी वाक्य (तथ्यों के पूल में एक राय की सजा क्यों चुनें ???) एक अस्वीकरण है ... हे, मैं नोड को संशोधित करने की कोशिश का समर्थन नहीं करता! लेकिन अगर आपको जरूरी है, तो आप ऐसा करते हैं। आप सही हो सकते हैं, अधिक सिंक कॉल के लिए कमरा हो सकता है और डेवलपर्स को यह तय करने देना है कि किस का उपयोग करना है, लेकिन अभी, नोड के डेवलपर्स ने फैसला किया है कि यह मामला नहीं है, जो वास्तव में मेरा मुद्दा है। – ChrisCM

+0

आपके प्रश्नों के अनुसार, दो कारणों से सिंक्रोनस एफएस विधियां मौजूद हैं। ए: प्रारंभिक चरण के हिस्से के रूप में कॉन्फ़िगरेशन जानकारी एकत्र करना अपेक्षाकृत सामान्य आवश्यकता है, और सरल समकालिक रूप से। बी: कुछ परिस्थितियों में एक श्रृंखला सिंक्रोनस डिस्क अनुरोध असीमित अनुरोधों के समूह के साथ डिस्क को बाढ़ करने से वास्तव में अधिक प्रदर्शन करने वाले हैं जो इसे संभालने के लिए तैयार नहीं हैं। सर्वर आईओ (डीडीओएस हमलों) के साथ भी यह सच है, यह केवल एक असीम (10000x की तरह) बनाने के लिए कठिन परिस्थिति है। हालांकि, एक डिस्क प्रक्रिया को अधिभारित करने के लिए एक प्रक्रिया के लिए बहुत आसान है और खुद को धीमा कर देता है। – ChrisCM

संबंधित मुद्दे