जब भी मैं स्थान बी पर अपना 'save_to_db' फ़ंक्शन चलाता हूं, तो यह विफल हो जाता है।

नीचे दिया गया कोड समस्या दिखाता है ...


//location A

var i = 0;
while(true)
{

    i++;
    if(i == 100)
    {

//location B

        save_to_db(newUnit, 11214.1, 'TEST');
    }

}


//location C

फ़ंक्शन 'save_to_db' स्थान ए और सी पर ठीक काम करता है लेकिन स्थान बी में विफल रहा।

मुझे लगता है कि ऐसा इसलिए है क्योंकि लूप अनंत और सिंक्रनाइज़ है। इसलिए यह नोडज को अपना इवेंट लूप चलाने का मौका नहीं देता है। हम इस मामले में नोडज को अपना इवेंट लूप चलाने का मौका कैसे दे सकते हैं?

=================================================== ===

उपरोक्त कोड कोड का बहुत ही सरल संस्करण है। मेरे पास 'db_util' नामक एक वर्ग/मॉड्यूल है और इसकी दो विधियां हैं, 'save_to_db' और 'read_from_db'। मुझे लगता है कि इन विधियों के कारण 'mysql' मॉड्यूल का उपयोग किया जाता है, वे डेटाबेस को एसिंक तरीके से एक्सेस करते हैं। लेकिन मेरा जबकि सच्चा लूप नोडज इवेंटलूप को ब्लॉक करता है। इसलिए लूप में न तो विधियों को लागू करने का मौका है।

var mysql = require('mysql');
var db_util = function()
{}

db_util.prototype = {
    save_to_db: function (neural_network, fitness, type) {
        var connection = mysql.createConnection({
            host: 'localhost',
            user: 'root',
            password: '',
            database: 'nodejstestdb'
        });
        connection.connect();      
        var addSql = 'INSERT INTO mytable(id, nn, type, fitness) VALUES(?,?,?,?)';
        var addSqlParams = [null, neural_network, type, fitness];
        connection.query(addSql, addSqlParams, function (err, result) {
            if (err) {
                console.log('[INSERT ERROR] - ', err.message);
                return;
            }                  
            console.log('INSERT ID:', result);          
        });
        connection.end();
    },


    read_from_db:function(){

        var connection = mysql.createConnection({
            host: 'localhost',
            user: 'root',
            password: '',
            database: 'nodejstestdb'
        });
        connection.connect();

        var sql = 'SELECT * FROM mytable ORDER BY fitness DESC'; 
        connection.query(sql, function (err, result) {
            if (err) {
                console.log('[SELECT ERROR] - ', err.message);
                return;
            }
            console.log(result);
            var nn = result[0].nn;            
            neural_network = synaptic.Network.fromJSON(JSON.parse(nn));           
            return neural_network;
        });
        connection.end();
    }
}

module.exports = db_util;


================ अपडेट 2 उत्तरों के कारण

let i = 0;
(function tick() {
    ++i;
    if (i%100 == 0) {
        save_to_db();
    }
    setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}());
let i = 0;
tick();

@ टी.जे. क्राउडर, सर आपके उत्तर के लिए धन्यवाद। लेकिन आपके उपरोक्त कोड और नीचे दिए गए कोड में क्या अंतर है?

var i = 0;

function tick() {
    ++i;
    if (i%100 == 0) {
        save_to_db();
    }
    setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}

tick();
0
wildcolor 25 जून 2019, 09:51

1 उत्तर

सबसे बढ़िया उत्तर

जैसा कि वीएलएजेड कहता है, मुझे आश्चर्य है कि आपको केवल इवेंट लूप का उपयोग करने के बजाय एक अनंत लूप की आवश्यकता क्यों है।

मुझे लगता है कि ऐसा इसलिए है क्योंकि लूप अनंत और सिंक्रनाइज़ है। इसलिए यह नोडज को अपना इवेंट लूप चलाने का मौका नहीं देता है।

हाँ, तुम बिल्कुल सही हो।

save_to_db कैसे काम करता है, यह जाने बिना इस प्रश्न का उत्तर देना कठिन है, लेकिन सामान्य तौर पर आपके पास तीन विकल्प होते हैं:

  1. setTimeout (या setImmediate) कॉलबैक की श्रृंखलाबद्ध श्रृंखला का उपयोग करें।

    • भिन्नता: आप काम का एक ब्लॉक करते हैं (जैसे, 100 पुनरावृत्तियों तक) और फिर अगले ब्लॉक को शेड्यूल करने के लिए setTimeout का उपयोग करें।
  2. एक async फ़ंक्शन और await का उपयोग करें (यदि save_to_db एक वादा लौटाता है, या एक वादा वापस करने के लिए संशोधित किया जा सकता है)।

  3. एक वर्कर थ्रेड का उपयोग करें, जो मुख्य थ्रेड पर एक संदेश पोस्ट करता है जब उसे save_to_db (तब वर्कर थ्रेड के ईवेंट लूप को ब्लॉक किया जाना मुख्य थ्रेड पर ईवेंट को नहीं रोकता है जिसकी save_to_db को आवश्यकता होती है)। (मैं शायद इसके लिए किसी कार्यकर्ता का उपयोग नहीं करूंगा।)


# 1 मोटे तौर पर इस तरह दिखता है:

let i = 0;
(function tick() {
    ++i;
    if (i == 100) {
        save_to_db();
    }
    setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}());

ध्यान दें कि Node.js दर-सीमा टाइमर, इसलिए setTimeout(tick, 0) जरूरी नहीं कि अगली कॉल को अगले इवेंट लूप पुनरावृत्ति पर शेड्यूल करे। आप इसके बजाय setImmediate का उपयोग कर सकते हैं, क्योंकि यह

I/O ईवेंट के कॉलबैक के बाद कॉलबैक के "तत्काल" निष्पादन को शेड्यूल करता है।

उदाहरण के लिए, यह कोड:

let i = 0;
let last = Date.now();
let sum = 0;
(function tick() {
    ++i;
    sum += Date.now() - last;
    if (i < 1000) {
        last = Date.now();
        setTimeout(tick, 0);
    } else {
        console.log(`Average: ${sum / i}`);
    }
})();

मेरे लिनक्स बॉक्स पर मेरे नोड v12.4 इंस्टॉलेशन पर 1.155ms के औसत बीता हुआ समय की रिपोर्ट करता है। setImmediate का उपयोग करने वाला समतुल्य कोड इसके बजाय औसतन केवल 0.004ms की रिपोर्ट करता है।

आपने एक टिप्पणी में कहा है कि आपको समझ में नहीं आया कि इसे "हिस्सा" में कैसे कार्यान्वित किया जाए। यहाँ एक उदाहरण है:

const chunkSize = 1000; // Or whatever
let i = 0;
(function chunk() {
    const chunkEnd = i + chunkSize;
    while (i++ < chunkEnd) {
        if (/*time to save to the DB*/) {
            // Note that we don't wait for it to complete, you've said it's
            // okay not to wait and that it's okay if they overlap
            save_to_db();
        }
    }
    setImmediate(chunk, 0);
})();

इसे इस तरह से करना, यह मुख्य धागे पर काम का एक हिस्सा करता है, फिर किसी भी I/O कॉलबैक की प्रसंस्करण की अनुमति देता है जिसे save_to_db की आवश्यकता हो सकती है, फिर चलती रहती है। आप इसे थोड़ा सा अनुकूलित कर सकते हैं केवल वापस उपज जब यह जानता है कि save_to_db के पास अभी भी काम करना है, लेकिन शायद यह इसे ओवरइंजीनियरिंग कर रहा है।


# 2 मोटे तौर पर इस तरह दिखता है:

(async () => {
    try {
        let i = 0;
        while (true) {
            if (i == 100) {
                await save_to_db();
            }
        }
    } catch (e) {
        // Handle/report error
    }
})();

#3 मैं पाठक के लिए एक अभ्यास के रूप में छोड़ दूंगा, लेकिन शायद मैं इसके लिए एक कार्यकर्ता का उपयोग नहीं करूंगा।

1
T.J. Crowder 25 जून 2019, 13:22