亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

nodejs中實現sleep功能實例

2019-11-20 12:52:20
字體:
來源:轉載
供稿:網友

nodejs最讓人不爽的就是其單線程特性,很多事情沒法做,對CPU密集型的場景,性能也不夠強勁。很長一段時間,我想在javascript語言框架下尋求一些解決方案,解決無法操作線程、性能差的問題。曾經最讓我印象深刻的方案是fibers,不過fibers也好,其他方案也好,在線程操作上還是很別扭,太過依賴輔助線程,本末倒置;就fiber而言,javascript固有的低性能問題并不能解決;最別扭的是在javascript語言框架下,線程間的消息傳遞常常很受限制,經常無法真正地共享對象。

nodejs的addon方式無疑是極好的,具有極強的靈活性、完備的功能和原生代碼的性能。簡單說就是讓nodejs直接調用c/c++模塊,是一種javascript和native的混合開發模式。好東西呀,為什么不用呢?addon應該算是一個大話題,今天我也不想太深入說這個,我自己的實踐也不是很多。那就實現一個sleep函數,就當是拋磚引玉吧。

sleep

為什么javascript實現不了真正的sleep?sleep方法是通過向操作系統內核注冊一個信號,指定時間后發送喚醒信號,而線程本身則掛起。本質上當線程 sleep(1000) 代表告訴操作系統:1000ms內不要給我分配CPU時間。所以sleep能保證線程掛起時不再占用CPU資源。而javascript是單線程運行,本身取消了線程的概念,自然沒有辦法將主線程掛起中斷。

也有人會嘗試用javascript方法要實現sleep,例如這樣:

復制代碼 代碼如下:

function sleep(sleepTime) {
    for(var start = +new Date; +new Date - start <= sleepTime; ) { }
}

這是采用空循環阻塞住主進程的運行來實現sleep,明顯跟真正的sleep相去甚遠。

那么如果實現一個真正的sleep呢?

環境準備

開發環境

之前我的一些博客已經說過,這里從略:node.js+npm、python 2.7、visual studio/ x-code。

 編譯工具

編譯工具需要采用node-gyp,較新版本的nodejs自帶此庫,如果沒有自帶node-gyp,請執行:

復制代碼 代碼如下:

npm install -g node-gyp

 gyp特性我沒有精力去研究,如果你比較熟悉gcc等其他編譯器,不排除gyp會有不兼容之處,而且編譯選項和開關也是不盡相同。建議針對nodejs重新編寫c++代碼,如果確實有模塊需要復用,可以考慮先用熟悉的gcc編譯成動態鏈接庫,再編寫少量代碼來使用動態鏈接庫,再把這部分代碼用gyp編譯出來供nodejs使用。

進入項目文件夾,執行 npm init 初始化項目。為了讓nodejs知道我們想制作addon,我們需要在package.json中添加:

復制代碼 代碼如下:

"gyp-file": true

如果使用過gcc,那么你一定記得makefile。類似的,gyp也是通過一個文件來描述編譯配置,這個文件為binding.gyp,它是一個我們非常熟悉的json文件。gyp不是我們探討的重點,所以binding.gyp也不會深入探究,我們只關注最重要的一些配置項。以下是一份簡單但完整的binding.gyp文件示例:

復制代碼 代碼如下:

{
  "targets": [
    {
      "target_name": "hello",
      "sources": [ "hello.cc" ],
      "include_dirs": [
        "<!(node -e /"require('nan')/")"
      ]
    }
  ]
}


就看看這里面涉及的三個配置項:

1.target_name:表示輸出出來的模塊名。
2.sources:表示需要編譯的源代碼路徑,這是一個數組。
3.include_dirs:表示編譯過程中要用到的目錄,這些目錄中的頭文件可以在預編譯指令 #include 搜索到。在這里使用了一個比較特殊的寫法,沒有把路徑用字符串常量給出,而是運行一個命令 node -e "require('nan')" ,nan庫后面再說,先看看這個命令輸出什么: node_modules/nan ,原來這句命令的意思是返回nan庫的路徑。

C++編碼

OK,既然已經配置了源代碼是hello.cc,那就建立一個這樣的文件。有一個問題需要提前提醒大家,我們所寫的c++模塊最終是要被v8引擎使用,所以api、寫法等受到v8引擎的制約。而不同版本的nodejs其實采用的v8引擎的版本也不盡相同,這也就意味著很難用一套c++代碼滿足不同版本的nodejs(指編譯過程,編譯完成后跨版本應該能夠使用,沒有驗證過。github不能上傳二進制類庫,所以github上開源會有麻煩。npm可以直接上傳二進制類庫,跳過編譯步驟,所以問題相對較?。?。

node 0.11及以上版本:

復制代碼 代碼如下:

#include <node.h>
#include <v8.h>

using namespace v8;

void SleepFunc(const v8::FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);
  double arg0 = args[0] -> NumberValue();
  Sleep(arg0);
}

void Init(Handle<Object> exports) {
  Isolate* isolate = Isolate::GetCurrent();
  exports->Set(String::NewFromUtf8(isolate, "sleep"),
      FunctionTemplate::New(isolate, SleepFunc)->GetFunction());
}

NODE_MODULE(hello, Init);

node 0.10及以下版本:

復制代碼 代碼如下:

#include <node.h>
#include <v8.h>

using namespace v8;

Handle<Value> SleepFun(const Arguments& args) {
  HandleScope scope; 
  double arg0 = args[0] -> NumberValue();
  Sleep(arg0);
  return scope.Close(Undefined());
}

void Init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("sleep"),
      FunctionTemplate::New(SleepFun)->GetFunction());
}

NODE_MODULE(hello, Init);


可以看出,變化還是相當大的,如果能屏蔽這些差異就太好了,有辦法了?我寫這么多還不就是想告訴你有辦法。是時候請出nan庫了。

nan

還記得在binding.gyp中,我們引入nan庫的路徑,就是要在這里用。nan庫是干嘛的呢?它提供了一層抽象,屏蔽了nodejs 0.8、nodejs 0.10、nodejs 0.12、io.js之前addon的語法差異。贊!

先安裝: npm install --save nan ,看看同樣的功能,用了nan后如何實現:

復制代碼 代碼如下:

#include <nan.h>
using namespace v8;

NAN_METHOD(Sleep){
    NanScope();
    double arg0=args[0]->NumberValue();
    Sleep(arg0);
    NanReturnUndefined();
}

void Init(Handle<Object> exports){
    exports->Set(NanSymbol("sleep"), FunctionTemplate::New(Sleep)->GetFunction());
}

NODE_MODULE(hello, Init);

你需要了解的就是nan這套東西,至于v8的那一套就可以不用關注。

從下往上看:

復制代碼 代碼如下:

NODE_MODULE(hello, Init);

 這句定義addon的入口。注意第一個參數要與我們在binding.gyp中target_name一項一致。第二個參數就是addon的入口函數。
 

復制代碼 代碼如下:

 void Init(Handle<Object> exports){
    exports->Set(NanSymbol("sleep"), FunctionTemplate::New(Sleep)->GetFunction());
}
 

 這段代碼就是addon的入口方法。它接收兩個參數,分別是exports和module。上面的示例省略了第二個參數。如果模塊提供一個對象,可以像示例中那個,直接給exports指定要提供的key-value;如果特殊一點,僅提供一個數值,或一個函數,則需要用到第二個參數,類似于 NODE_SET_METHOD(module, "exports", foo); 。這個示例中是表示要輸出這樣一個模塊:

復制代碼 代碼如下:

{
    "sleep": Sleep
}

Sleep是一個函數,下來就來看看Sleep的定義:

復制代碼 代碼如下:

NAN_METHOD(Sleep){
    NanScope();
    double arg0=args[0]->NumberValue();
    Sleep(arg0);
    NanReturnUndefined();
}

其實就是讀取javascript傳入的參數,轉成double型,再調用c++的sleep方法。

編譯addon

下面就要開始編譯這個模塊了。首先執行 node-gyp configure 來進行構建前準備工作,它會生成一個build文件夾和一些文件。接下來運行 node-gyp build 就可以開始編譯了。在這個示例中,最終會在/build/Release/目錄下生成一個hello.node文件,這就是最終能被javascript引用的addon模塊了。

如果后續對c++代碼有修改,就不用再運行 node-gyp configure ,直接運行 node-gyp build 就好。

nodejs使用

建立一個index.js,看看怎么用這個模塊吧:

復制代碼 代碼如下:

var sleep=require('./build/Release/hello.node').sleep;

console.log(new Date);
sleep(1000);
console.log(new Date);

// result
// Wed Mar 04 2015 14:55:18 GMT+0800 (中國標準時間)
// Wed Mar 04 2015 14:55:19 GMT+0800 (中國標準時間)       

很容易吧,跟普通的javascript函數的使用方式一模一樣。

至此本文想要分享的技術要點已經闡述完了。不過……究竟跟開篇提供的方法比起來有什么不一樣?我不截圖了,直接說明結果:

由于addon方式采用的方法是線程掛起,理論上不會有CPU占用和內存變化,結果也是驗證了這一點。再看javascript循環模擬sleep的方式,因為一直在跑循環,內存增加一點可以理解,沒什么大不了;再看CPU占用25%,似乎還算過得去。真的是這樣嗎?揭露真相的時候到了。我測試的筆記本電腦的CPU是雙核四線程,再結合25%的CPU占用……難道雙核四線程中有一個線程就被這個sleep給占用了?其實我發現這期間并沒有一個線程被鎖死,不過這不是javascript的功勞,而是intel超線程的功勞。因為說是四線程,其實本質是兩個處理核心只能是雙線程,只是cpu做了一個時間片切割上的小把戲。例如核心cpu01分成了t0和t2,假設在n tick(調度周期)后的一個tick內,任務會分到t0,那么在再后面一個tick,任務會分到t2。所以從一個比較長的時間尺度(相對于調度周期),一個任務在t0和t2上運行的時間基本是相當的。于是呈現出來的情景是nodejs的進程沒有占用t0或t2到100%,而是分別占用了50%上下。由于windows的進程調度相對比較復雜,所以CPU占用量上下浮動很大。可以這樣預測,如果是雙核雙線程的CPU來處理這個腳本,CPU占用會上升到50%,并且一個核心卡死。如果是單核CPU來處理,CPU一下子會上升到100%。

好像CPU這段說得有點多,超線程那些也是猜測,各位看看就好。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日本伊人精品一区二区三区介绍| 国产精品av免费在线观看| 亚洲人成在线一二| 亚洲女人被黑人巨大进入al| 日韩理论片久久| 日韩免费不卡av| 91国内精品久久| 成人福利免费观看| 日韩久久精品电影| 不卡av日日日| 欧美肥老妇视频| 午夜精品福利在线观看| 91亚洲精品久久久| xx视频.9999.com| 欧美一乱一性一交一视频| 欧美一级视频在线观看| 亚洲片在线观看| 国产欧洲精品视频| 欧美日韩成人精品| 亚洲第一精品夜夜躁人人爽| 国内精品国产三级国产在线专| 8090成年在线看片午夜| 国产精品国产三级国产aⅴ9色| 日韩中文在线视频| 91亚洲精品一区二区| 亚洲精品狠狠操| 久久人人爽人人爽人人片av高清| 亚洲人成啪啪网站| 亚洲人成网站色ww在线| 欧美日韩高清区| 亚洲网站在线观看| 亚洲最大激情中文字幕| 亚洲欧美国产精品专区久久| 欧美激情中文网| 一区二区日韩精品| 亚洲国产精品va| 成人黄色免费在线观看| 国产精品久久久久77777| 欧美多人乱p欧美4p久久| 亚洲成人亚洲激情| 亚洲一区二区三区在线免费观看| 国产成人久久久精品一区| 亚洲欧美国产va在线影院| 精品一区二区三区电影| 欧美性感美女h网站在线观看免费| 欧美在线影院在线视频| 国产亚洲免费的视频看| 国产精品久久电影观看| 国产日韩精品在线| 成人有码在线播放| 97人人做人人爱| 性欧美xxxx| 国产精品丝袜白浆摸在线| 成人av番号网| 亚洲欧美中文日韩v在线观看| 亚洲国产天堂久久综合网| 亚洲国产精品女人久久久| 青青草原成人在线视频| 日韩欧美综合在线视频| 国产视频精品在线| 日韩欧美国产成人| 日韩av在线天堂网| 精品国产自在精品国产浪潮| 久久偷看各类女兵18女厕嘘嘘| 国产第一区电影| 欧美性生交大片免网| 久久91亚洲精品中文字幕| 羞羞色国产精品| 欧美日韩国产页| 亚洲国产91精品在线观看| 日韩av在线看| 亚洲精品美女网站| 亚洲自拍另类欧美丝袜| 国产精品劲爆视频| 一区二区在线视频| 国内精久久久久久久久久人| 国产99久久精品一区二区 夜夜躁日日躁| 国产精品久久不能| 欧美性视频在线| 久久亚洲一区二区三区四区五区高| 欧美激情欧美激情在线五月| 亚洲欧美一区二区三区在线| 亚洲亚裔videos黑人hd| 九九热这里只有在线精品视| 欧美大片网站在线观看| 成人精品视频久久久久| 国产一区二区三区在线观看视频| 国产一区二区三区18| 91av国产在线| 国产精品88a∨| 色777狠狠综合秋免鲁丝| 日韩电影大全免费观看2023年上| 国产玖玖精品视频| 国产精品三级久久久久久电影| 日韩欧美亚洲范冰冰与中字| 国产激情999| 九九精品视频在线| 中文字幕欧美日韩在线| 欧美在线视频一二三| 国产精品久久色| 亚洲欧美激情四射在线日| 麻豆乱码国产一区二区三区| 日韩一二三在线视频播| 78m国产成人精品视频| 成人观看高清在线观看免费| 国产精品福利无圣光在线一区| 久久久久在线观看| 欧美高清视频免费观看| 亚洲人成网站777色婷婷| 久久亚洲国产精品成人av秋霞| 欧美精品一区二区免费| 欧美老少做受xxxx高潮| 日韩精品在线免费播放| 成人国产精品久久久久久亚洲| 亚洲国产精品va| 日本不卡高字幕在线2019| 精品久久久久久| 欧美极品第一页| 一区二区三区日韩在线| 国产一区二区美女视频| 91麻豆国产语对白在线观看| 精品无码久久久久久国产| 成人免费在线网址| 欧美重口另类videos人妖| 色妞欧美日韩在线| 久久人人爽人人爽人人片av高清| 国产日韩欧美在线看| 91九色视频导航| 欧美极品欧美精品欧美视频| 国产69久久精品成人看| 亚洲精品自拍偷拍| 91在线播放国产| 日韩高清av一区二区三区| 不卡中文字幕av| 国产成人自拍视频在线观看| 国产精品久久久av| 68精品国产免费久久久久久婷婷| 日韩视频亚洲视频| 欧美午夜视频一区二区| 日韩在线视频一区| 亚洲黄在线观看| 色多多国产成人永久免费网站| 久久精品国产v日韩v亚洲| 欧美性受xxxx黑人猛交| 日韩av高清不卡| 亚洲第一精品福利| 国内免费精品永久在线视频| 国产美女精品免费电影| 欧美精品www在线观看| 国产亚洲精品久久| 在线日韩日本国产亚洲| 日韩美女视频在线观看| 久久精品国产亚洲| 激情久久av一区av二区av三区| 91欧美精品午夜性色福利在线| 成人在线小视频| 欧美疯狂xxxx大交乱88av| 久久久久久18| 91精品国产乱码久久久久久久久| 亚洲图片在区色| 欧美日韩亚洲一区二区| 亚洲成人亚洲激情| 久久久精品久久久| 热久久免费国产视频|