成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

使用node子進(jìn)程spawn,exec踩過的坑

cppprimer / 3860人閱讀

摘要:最后發(fā)現(xiàn)使用子進(jìn)程打開還真的就是使用到一定程度就掛掉。上面的簡(jiǎn)單流程就是啟動(dòng)一個(gè)子進(jìn)程。邏輯就是,記錄子進(jìn)程的大小,一旦超過就掉子進(jìn)程。我們?cè)谑褂脮r(shí),不知道設(shè)置,默認(rèn)的是當(dāng)我們子進(jìn)程日志達(dá)到時(shí),自動(dòng)掉了。

如何在項(xiàng)目中實(shí)現(xiàn)熱更新中提到的一個(gè)坑child_process的exec使用問題,下面文章會(huì)詳細(xì)介紹下,debug到node源碼中的詳細(xì)介紹,不容錯(cuò)過。

child_process介紹

Nodejs是單線程單進(jìn)程的,但是有了child_process模塊,可以在程序中直接創(chuàng)建子進(jìn)程,并使用主進(jìn)程和子進(jìn)程之間實(shí)現(xiàn)通信。

對(duì)于child_process的使用,大家可以找找其他文章,介紹還是比較多的,本文主要講一下踩過的坑。

踩過的坑

在使用EHU(esl-hot-update)這個(gè)工具時(shí)(對(duì)于工具的介紹,參考前面的文章如何在項(xiàng)目中實(shí)現(xiàn)熱更新),發(fā)現(xiàn)用子進(jìn)程啟動(dòng)項(xiàng)目,經(jīng)常性的掛掉。然后也不知道為什么,甚至懷疑子進(jìn)程的效率比較低。

最后為了進(jìn)一步驗(yàn)證,在同樣的環(huán)境下,一個(gè)直接啟動(dòng)服務(wù),一個(gè)是使用require("child_process").exec("...") 方式啟動(dòng)。

最后發(fā)現(xiàn)使用子進(jìn)程打開還真的就是使用到一定程度就掛掉。雖然此時(shí)也沒有什么解決方案,但是至少能把問題定位在子進(jìn)程上了,而不是其他工具代碼導(dǎo)致程序掛掉。

定位問題

定位了問題后,網(wǎng)上查找child_process相關(guān)資料,發(fā)現(xiàn)exec與spawn方法的區(qū)別與陷阱 這篇文章提到幾點(diǎn):

exec與spawn是有區(qū)別的

exec是對(duì)spawn的一個(gè)封裝

最重要的exec比spawn多了一些默認(rèn)的option

基于以上幾點(diǎn)有些頭緒了,但是還是沒有明確的解決方案。

最后一個(gè)辦法,直接斷點(diǎn)到nodejs的child_process.js模塊中嘗試看看問題出在哪里。

exec和spawn的源碼區(qū)分

斷點(diǎn)進(jìn)去看后,豁然開朗,exec是對(duì)execFile的封裝,execFile又是對(duì)spawn 的封裝。

每一層封裝都是加強(qiáng)一些易用性以及功能。

直接看源碼:

exports.exec = 
    function(command /*, options, callback*/) {
          var opts = normalizeExecArgs.apply(null, arguments);
          return exports.execFile(opts.file,
                                  opts.args,
                                  opts.options,
                                  opts.callback);
};

exec對(duì)于execFile的封裝是進(jìn)行參數(shù)處理

處理的函數(shù):

normalizeExecArgs

關(guān)鍵邏輯

if (process.platform === "win32") {
    file = process.env.comspec || "cmd.exe";
    args = ["/s", "/c", """ + command + """];
    // Make a shallow copy before patching so we don"t clobber the user"s
    // options object.
    options = util._extend({}, options);
    options.windowsVerbatimArguments = true;
  } else {
    file = "/bin/sh";
    args = ["-c", command];
  }

將簡(jiǎn)單的command命名做一個(gè),win和linux的平臺(tái)處理。

此時(shí)execFile接受到的就是一個(gè)區(qū)分平臺(tái)的command參數(shù)。

然后重點(diǎn)來了,繼續(xù)debug,execFile中:

var options = {
    encoding: "utf8",
    timeout: 0,
    maxBuffer: 200 * 1024,
    killSignal: "SIGTERM",
    cwd: null,
    env: null
};

有這么一段,設(shè)置了默認(rèn)的參數(shù)。然后后面又是一些參數(shù)處理,最后調(diào)用spawn方法啟動(dòng)子進(jìn)程。

上面的簡(jiǎn)單流程就是啟動(dòng)一個(gè)子進(jìn)程。到這里都沒有什么問題。

繼續(xù)看,重點(diǎn)又來了:

用過子進(jìn)程應(yīng)該知道這個(gè)child.stderr

下面的代碼就解答了為什么子進(jìn)程會(huì)掛掉。

child.stderr.addListener("data", function(chunk) {
    stderrLen += chunk.length;

    if (stderrLen > options.maxBuffer) {
      ex = new Error("stderr maxBuffer exceeded.");
      kill();
    } else {
      if (!encoding)
        _stderr.push(chunk);
      else
        _stderr += chunk;
    }
});

邏輯就是,記錄子進(jìn)程的log大小,一旦超過maxBufferkill掉子進(jìn)程。

原來真相在這里。我們?cè)谑褂?b>exec時(shí),不知道設(shè)置maxBuffer,默認(rèn)的maxBuffer是200K,當(dāng)我們子進(jìn)程日志達(dá)到200K時(shí),自動(dòng)kill()掉了。

exec和spawn的使用區(qū)分

不過exec確實(shí)比spawn在使用上面要好很多

例如我們執(zhí)行一個(gè)命令

使用exec

require("child_process").exec("edp webserver start");

使用spawn

linux下這么搞

var child = require("child_process").spawn(
   "/bin/sh", 
   ["-c","edp webserver start"],
   {
       cwd: null,
       env: null,
       windowsVerbatimArguments: false
   }
);

win下

var child = require("child_process").spawn(
   "cmd.exe",
   ["/s", "/c", "edp webserver start"],
   {
       cwd: null,
       env: null,
       windowsVerbatimArguments: true
   }
);

可見spawn還是比較麻煩的。

解決方案

知道上面原因了,解決方案就有幾個(gè)了:

子進(jìn)程的系統(tǒng),不再輸出日志

maxBuffer這個(gè)傳一個(gè)足夠大的參數(shù)

直接使用spawn,放棄使用exec

我覺得最優(yōu)的方案是直接使用spawn,解除maxBuffer的限制。但是實(shí)際處理中,發(fā)現(xiàn)直接考出normalizeExecArgs這個(gè)方法去處理平臺(tái)問題,在win下還是有些不好用,mac下沒有問題。所以暫時(shí)將maxBuffer設(shè)置了一個(gè)極大值,保證大家的正常使用。然后后續(xù)在優(yōu)化成spawn方法。

吐槽

其實(shí)沒有怎么理解,execFile對(duì)于spawn封裝加maxBuffer的這個(gè)邏輯,而且感覺就算加了,是否也可以給一個(gè)方式,去掉maxBuffer的限制。

難道是子進(jìn)程的log量會(huì)影響性能?

感想

其實(shí)在解決這個(gè)問題時(shí),發(fā)現(xiàn)這個(gè)差異/坑還比較意外,因?yàn)樽陨韺?duì)于node其實(shí)還不是很熟,這個(gè)子進(jìn)程的使用其實(shí)也是在ehu中第一次遇到。

感受比較多的就是有時(shí)候正對(duì)問題去學(xué)習(xí)/研究,其實(shí)效率特別高。

微信公眾號(hào)

博客地址

http://tangguangyao.github.io/

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/78332.html

相關(guān)文章

  • 記錄我開發(fā)gpm,Git倉(cāng)庫(kù)管理工具的歷程

    摘要:前言記錄下開發(fā)的一些事,加強(qiáng)自己對(duì)的應(yīng)用。雛形參考于的項(xiàng)目管理,發(fā)現(xiàn)非常的優(yōu)雅。嘗試通過修改權(quán)限為,最后無果不了了之。方式二詢問篩選會(huì)在終端監(jiān)聽輸入的關(guān)鍵字,根據(jù)關(guān)鍵字篩選出一系列的倉(cāng)庫(kù)。自己也在使用,打算長(zhǎng)期維護(hù)。 前言 記錄下開發(fā)的一些事,加強(qiáng)自己對(duì)nodejs的應(yīng)用。共勉! 有讓你操蛋的事,就有需求 對(duì)于經(jīng)常參與開源貢獻(xiàn),或者看見某些庫(kù),像試試手的人來說,經(jīng)常需要git clon...

    thursday 評(píng)論0 收藏0
  • Node.js中spawnexec的異同比較

    摘要:返回值對(duì)象利用給定的命令以及參數(shù)執(zhí)行一個(gè)新的進(jìn)程,如果沒有參數(shù)數(shù)組,那么將默認(rèn)是一個(gè)空數(shù)組。當(dāng)子進(jìn)程執(zhí)行完畢后將會(huì)執(zhí)行的回調(diào)函數(shù),參數(shù)有返回值對(duì)象在中運(yùn)行一個(gè)命令,并緩存命令的輸出。 前言 眾所周知,Node.js在child_process模塊中提供了spawn和exec這兩個(gè)方法,用來開啟子進(jìn)程執(zhí)行指定程序。這兩個(gè)方法雖然目的一樣,但是既然Node.js為我們提供了兩個(gè)方法,那它...

    garfileo 評(píng)論0 收藏0
  • nodeJS多進(jìn)程

    摘要:通過將的給出來的進(jìn)程。恩吞吐率關(guān)于吞吐率有多種解讀,一種是描繪服務(wù)器單位時(shí)間處理請(qǐng)求的能力。而根據(jù)這個(gè)描述的話他的單位就為而這個(gè)指標(biāo)就是上面數(shù)據(jù)中的當(dāng)然,肯定是越大越好了吞吐量這個(gè)和上面的吞吐率很有點(diǎn)關(guān)系的。 首先鄭重聲明:nodeJS 是一門單線程!異步!非阻塞語言!nodeJS 是一門單線程!異步!非阻塞語言!nodeJS 是一門單線程!異步!非阻塞語言! 重要的事情說3遍。 因?yàn)?..

    happen 評(píng)論0 收藏0
  • nodeJS多進(jìn)程

    摘要:通過將的給出來的進(jìn)程。恩吞吐率關(guān)于吞吐率有多種解讀,一種是描繪服務(wù)器單位時(shí)間處理請(qǐng)求的能力。而根據(jù)這個(gè)描述的話他的單位就為而這個(gè)指標(biāo)就是上面數(shù)據(jù)中的當(dāng)然,肯定是越大越好了吞吐量這個(gè)和上面的吞吐率很有點(diǎn)關(guān)系的。 首先鄭重聲明:nodeJS 是一門單線程!異步!非阻塞語言!nodeJS 是一門單線程!異步!非阻塞語言!nodeJS 是一門單線程!異步!非阻塞語言! 重要的事情說3遍。 因?yàn)?..

    james 評(píng)論0 收藏0
  • Node.js child_process模塊解讀

    摘要:而且方式創(chuàng)建的子進(jìn)程與父進(jìn)程之間建立了通信管道,因此子進(jìn)程和父進(jìn)程之間可以通過的方式發(fā)送消息。與事件的回調(diào)函數(shù)有兩個(gè)參數(shù)和,代碼子進(jìn)程最終的退出碼,如果子進(jìn)程是由于接收到信號(hào)終止的話,會(huì)記錄子進(jìn)程接受的值。 在介紹child_process模塊之前,先來看一個(gè)下面的代碼。 const http = require(http); const longComputation = () =>...

    baiy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<