This article mainly introduces the implementation of sleep function instances in nodejs. This article describes the development process and performance testing of the sleep function, for more information about node. JS, the most unpleasant thing is its single-threaded feature. Many things cannot be done. For CPU-intensive scenarios, the performance is not strong enough. For a long time, I wanted to seek some solutions under the javascript framework to solve the problem of being unable to operate the thread and poor performance. The solution that impressed me the most once was fibers, but it was also good for fibers and other solutions. It was quite awkward in thread operations. It was too dependent on the auxiliary thread and put the cart before the horse. For fiber, the inherent low performance of javascript cannot be solved. The most awkward thing is that under the javascript framework, message transmission between threads is often restricted and objects cannot be truly shared.
The addon method of nodejs is undoubtedly excellent, with strong flexibility, complete functions, and native code performance. Simply put, it allows nodejs to directly call the c/c ++ module. It is a mixed development mode of javascript and native. Good stuff. Why not? Addon should be a big topic. Today, I don't want to talk about it too deeply, and I don't have many practices. Implement a sleep function.
Sleep
Why cannot javascript achieve true sleep? The sleep method registers a signal to the operating system kernel, sends a wake-up signal after a specified time, And the thread itself suspends. Essentially, when the thread sleep (1000) means to tell the operating system: do not allocate CPU time to me within Ms. So sleep can ensure that the thread does not occupy CPU resources when it is suspended. While javascript runs in a single thread, it removes the concept of a thread and naturally cannot suspend or interrupt the main thread.
Some people will try to use javascript to implement sleep, for example:
The Code is as follows:
Function sleep (sleepTime ){
For (var start = + new Date; + new Date-start <= sleepTime ;){}
}
This uses an empty loop to block the running of the main process to achieve sleep, which is obviously far from the real sleep.
What if we implement a real sleep?
Environment preparation
Development Environment
Some of my blogs have said that node. js + npm, python 2.7, visual studio/x-code.
Compilation tool
The compilation tool must use node-gyp. Later versions of nodejs come with this library. If node-gyp is not provided, run the following command:
The Code is as follows:
Npm install-g node-gyp
Gyp features I have no energy to study. If you are familiar with other compilers such as gcc, It is not ruled out that gyp will be incompatible, and the compilation options and switches are also different. We recommend that you re-compile the c ++ code for nodejs. If some modules need to be reused, You can first compile the familiar gcc into a dynamic link library, and then write a small amount of code to use the dynamic link library, compile the code using gyp for nodejs.
Go to the project folder and run npm init to initialize the project. To let nodejs know that we want to create addon, we need to add the following in package. json:
The Code is as follows:
"Gyp-file": true
If you have used gcc, remember makefile. Similarly, gyp describes the compilation configuration through a file, which is binding. gyp, which is a json file that we are very familiar. Gyp is not the focus of our discussion, so binding. gyp will not be further explored. We only focus on the most important configuration items. The following is an example of a simple but complete binding. gyp file:
The Code is as follows:
{
"Targets ":[
{
"Target_name": "hello ",
"Sources": ["hello. cc"],
"Include_dirs ":[
" ]
}
]
}
Let's take a look at the three configuration items involved:
1.tar get_name: name of the output module.
2. sources: indicates the source code path to be compiled. This is an array.
3. include_dirs: indicates the directory to be used during compilation. the header files in these directories can be searched in the pre-compilation command # include. A special method is used here. Instead of providing the path with a String constant, a command node-e "require ('nan ')" is run, first, let's take a look at the output of this command: node_modules \ nan. The original meaning of this command is to return the path of the nan library.
C ++ Encoding
OK. Now that the source code is configured as hello. cc, create a file like this. There is a problem that we need to remind you in advance that the c ++ module we wrote will eventually be used by the v8 engine, so api and writing are restricted by the v8 engine. Different Versions of nodejs actually use different v8 engine versions, which means it is difficult to use a set of c ++ code to meet different versions of nodejs (refer to the compilation process, it should be usable across versions after compilation, and has not been verified. Github cannot upload binary class libraries, so it is troublesome to open source on github. Npm can directly upload binary class libraries and skip the compilation steps, so the problem is relatively small ).
Node 0.11 and later versions:
The Code is as follows:
# Include
# Include
Using namespace v8;
Void SleepFunc (const v8: FunctionCallbackInfo & Args ){
Isolate * isolate = Isolate: GetCurrent ();
HandleScope scope (isolate );
Double arg0 = args [0]-> NumberValue ();
Sleep (arg0 );
}
Void Init (HandleExports ){
Isolate * isolate = Isolate: GetCurrent ();
Exports-> Set (String: NewFromUtf8 (isolate, "sleep "),
FunctionTemplate: New (isolate, SleepFunc)-> GetFunction ());
}
NODE_MODULE (hello, Init );
Node 0.10 and earlier versions:
The Code is as follows:
# Include
# Include
Using namespace v8;
Handle SleepFun (const Arguments & args ){
HandleScope scope;
Double arg0 = args [0]-> NumberValue ();
Sleep (arg0 );
Return scope. Close (Undefined ());
}
Void Init (HandleExports ){
Exports-> Set (String: NewSymbol ("sleep "),
FunctionTemplate: New (SleepFun)-> GetFunction ());
}
NODE_MODULE (hello, Init );
It can be seen that the changes are quite large. It would be great to block these differences. Is there a solution? I don't want to tell you how to write so much. It is time to release the nan database.
Nan
Remember to introduce the path of the nan library in binding. gyp, Which is used here. What does nan database do? It provides an abstraction layer that shields the syntax differences of addon before nodejs 0.8, nodejs 0.10, nodejs 0.12, and io. js. Like!
First install: npm install -- save nan to see how to implement the same function after nan is used:
The Code is as follows:
# Include
Using namespace v8;
NAN_METHOD (Sleep ){
NanScope ();
Double arg0 = args [0]-> NumberValue ();
Sleep (arg0 );
NanReturnUndefined ();
}
Void Init (HandleExports ){
Exports-> Set (NanSymbol ("sleep"), FunctionTemplate: New (Sleep)-> GetFunction ());
}
NODE_MODULE (hello, Init );
What you need to know is the nan set. You don't need to pay attention to the v8 set.
From the bottom up:
The Code is as follows:
NODE_MODULE (hello, Init );
This sentence defines the endpoint of addon. Note that the first parameter must be consistent with target_name in binding. gyp. The second parameter is the addon entry function.
The Code is as follows:
Void Init (HandleExports ){
Exports-> Set (NanSymbol ("sleep"), FunctionTemplate: New (Sleep)-> GetFunction ());
}
This code is the addon entry method. It receives two parameters: exports and module. The second parameter is omitted in the preceding example. If the module provides an object, you can directly specify the key-value to be provided for exports, as in the example. If it is special, only one value or one function is provided, the second parameter is required, similar to NODE_SET_METHOD (module, "exports", foo );. In this example, a module is output:
The Code is as follows:
{
"Sleep": Sleep
}
Sleep is a function. Let's take a look at the definition of Sleep:
The Code is as follows:
NAN_METHOD (Sleep ){
NanScope ();
Double arg0 = args [0]-> NumberValue ();
Sleep (arg0 );
NanReturnUndefined ();
}
In fact, it is to read the parameters passed in by javascript, convert them to the double type, and then call the sleep method of c ++.
Compile addon
Compile this module. First, execute node-gyp configure to prepare for building. It will generate a build folder and some files. Run node-gyp build to start compiling. In this example, a hello. node file is generated in the/build/Release/directory, which is the addon module that can be referenced by javascript.
If you modify the c ++ code in the future, you do not need to run node-gyp configure, just run node-gyp build directly.
Nodejs usage
Create an index. js and see how to use this module:
The Code is as follows:
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 (Chinese Standard Time)
// Wed Mar 04 2015 14:55:19 GMT + 0800 (Chinese Standard Time)
It's easy, just like using common javascript Functions.
The technical points to be shared in this article have been elaborated. But ...... What is the difference between the method and the method provided at the beginning? I can't, just explain the results:
Because the addon method adopts thread suspension, theoretically there will be no CPU usage or memory changes, and the results also verify this. Let's look at the javascript loop to simulate sleep. Because we have been running the loop, we can understand the memory increase. It's no big deal. We can see that the CPU usage is 25%, which seems to be a good deal. Is that true? It's time to reveal the truth. The CPU of the laptop I tested is a dual-core quad-thread, combined with 25% CPU usage ...... Is there a thread in the dual-core and four-line processes occupied by this sleep? In fact, I found that no thread was locked during this period, but this is not the credit of javascript, but the credit of intel hyper-threading. Because there are four threads, the essence is that the two processing cores can only be dual threads, but the cpu performs a time slice cutting trick. For example, the core CPU 01 is divided into t0 and t2. if the task is assigned to t0 in a tick after the n tick (scheduling cycle), the task is assigned to T2. Therefore, from a relatively long time scale (relative to the scheduling cycle), the running time of a task on t0 and t2 is basically equivalent. As a result, the node. js process does not occupy t0 or t2 to 100%, but occupies up or down 50% respectively. Because the process scheduling in windows is relatively complex, the CPU usage fluctuates greatly. It can be predicted that if the dual-core dual-thread CPU is used to process this script, the CPU usage will increase to 50%, and a core will be stuck. If it is a single-core CPU, the CPU will suddenly rise to 100%.
It seems that the CPU section is a bit more, and those with hyper-threading are also guesses. Let's take a look.