One of the most unpleasant things about Nodejs is its single-threaded features, which are impossible to do, and are not strong enough for CPU-intensive scenarios. For a long time, I wanted to find some solutions under the JavaScript language framework to solve the problem of inability to manipulate threads and poor performance. I have been most impressed with the program is fibers, but fibers or other schemes, the online operation is still very awkward, too dependent on the auxiliary thread, put the cart before the horse; As far as fiber is concerned, the inherent low performance problem of JavaScript does not solve ; The most awkward thing is that in the JavaScript language framework, messaging between threads is often limited and often fails to truly share objects.
Nodejs's addon approach is undoubtedly excellent, with strong flexibility, complete functionality and native code performance. To put it simply, it is a hybrid development model of JavaScript and native to let Nodejs directly call the C + + module. Good thing, why not? Addon should be considered a big topic, today I do not want to go too deep to say this, my own practice is not a lot. Then realize a sleep function, just as a trigger.
Sleep
Why can't javascript achieve real sleep? The Sleep method is to send a wake-up signal after a specified time by registering a signal to the operating system kernel, while the thread itself hangs. Essentially when the thread sleep (1000) rep tells the operating system: Do not allocate CPU time to me within 1000ms. So sleep ensures that the thread hangs without consuming CPU resources. And JavaScript is single-threaded running, itself canceling the concept of the thread, there is no way to suspend the main thread interrupt.
Others will try to implement sleep using JavaScript methods, such as this:
Copy Code code as follows:
function Sleep (sleeptime) {
for (var start = +new Date; +new date-start <= sleeptime;) { }
}
This is the use of an empty loop to block the operation of the main process to achieve sleep, obviously with the true sleep far apart.
So what if you realize a real sleep?
Environmental preparedness
Development environment
As some of my blogs have said before, here are Conlio: node.js+npm, Python 2.7, visual Studio/x-code.
Compiling tools
The compiler tool needs to take the NODE-GYP, the newer version of the Nodejs to bring this library, if not the NODE-GYP, please do:
Copy Code code as follows:
Gyp features I have no energy to study, if you are more familiar with GCC and other compilers, do not rule out the Gyp will be incompatible, and the compilation options and switches are also different. It is recommended to rewrite C + + code for NODEJS, if you do have a module need to reuse, you can consider using the familiar GCC compiled into a dynamic link library, and then write a small number of code to use the dynamic link library, and then this part of the code with GYP compiled for Nodejs use.
Go to the project folder and perform the NPM init initialization project. In order for Nodejs to know that we want to make addon, we need to add in Package.json:
Copy Code code as follows:
If you have used GCC, then you must remember makefile. Similarly, Gyp is also a file to describe the compilation configuration, this file is Binding.gyp, it is a very familiar JSON file. Gyp is not the focus of our discussion, so Binding.gyp will not delve into it, we only focus on some of the most important configuration items. The following is a simple but complete example of a Binding.gyp file:
Copy Code code as follows:
{
"Targets": [
{
"Target_name": "Hello",
"Sources": ["hello.cc"],
"Include_dirs": [
"<! (NODE-E \ "require (' Nan ')") "
]
}
]
}
Take a look at the three configuration items that are involved:
1.target_name: The name of the module that represents the output.
2.sources: Indicates the source code path that needs to be compiled, this is an array.
3.include_dirs: Represents the directories that are used during compilation, and the header files in these directories can be searched #include the precompiled instruction. Here we use a special method of writing, not to give the path in string constants, but to run a command node-e "require (' Nan ')", after Nan Library, look at the output of this command first: Node_modules\nan, The original meaning of this command is to return the path of the Nan library.
C + + encoding
OK, now that you have configured the source code is hello.cc, create a file like this. There is a problem to remind everyone in advance, we write the C + + module is ultimately to be used by the V8 engine, so the API, writing, etc. by the V8 engine constraints. and different versions of the Nodejs in fact, the version of the V8 engine is not the same, which means it is difficult to use a set of C + + code to meet different versions of the Nodejs (refers to the compilation process, the compilation is completed after the cross version should be able to use, has not been validated. GitHub can not upload the binary class library, so GitHub open source will have trouble. NPM can upload the binary class library directly, skipping the compile steps, so the problem is relatively small.
Node 0.11 and above:
Copy Code code as follows:
#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 and the following versions:
Copy Code code as follows:
#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);
It can be seen that the change is still quite large, if you can shield these differences is too good, there is a way? I've written so much to tell you that there is a way. It's time to take out Nan Ku.
Nan
Remember that in the BINDING.GYP, we introduced the Nan Library path, which is used here. What's Nan's library for? It provides a layer of abstraction that masks the syntactic differences of addon before Nodejs 0.8, Nodejs 0.10, Nodejs 0.12, and Io.js. Praise!
Install First: npm install--save nan, look at the same function, use Nan after how to implement:
Copy Code code as follows:
#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);
You need to know is Nan this set of things, as for the V8 of the set can not be concerned about.
Look up from the bottom:
Copy Code code as follows:
Node_module (Hello, Init);
This defines the entrance to the addon. Note that the first parameter should be consistent with our target_name in Binding.gyp. The second parameter is the Addon entry function.
Copy Code code as follows:
void Init (handle<object> exports) {
Exports->set (NaNSymbol ("Sleep"), functiontemplate::new (Sleep)->getfunction ());
}
This code is the Addon entry method. It receives two parameters, namely exports and module. The previous example omits the second argument. If the module provides an object, like the one in the example, specify the Key-value to be supplied directly to exports, and if it is special to provide only a numeric value, or a function, you need to use the second argument, similar to the Node_set_method (module, " Exports ", foo); This example indicates that you want to export such a module:
Copy Code code as follows:
Sleep is a function that comes down to see the definition of sleep:
Copy Code code as follows:
Nan_method (Sleep) {
Nanscope ();
Double Arg0=args[0]->numbervalue ();
Sleep (arg0);
Nanreturnundefined ();
}
In fact, read the parameters that JavaScript passed in, turn to double, and then call the C + + sleep method.
Compiling addon
The following is the beginning of compiling this module. The first step is to perform the NODE-GYP configure preparation, which generates a build folder and some files. Then run the Node-gyp build to start compiling. In this example, a Hello.node file is eventually generated in the/build/release/directory, which is the addon module that can eventually be referenced by JavaScript.
If the subsequent changes to C + + code, you do not have to run NODE-GYP configure, directly run Node-gyp build is good.
Nodejs use
Build a index.js and see how to use this module:
Copy Code code as follows:
var sleep=require ('./build/release/hello.node '). Sleep;
Console.log (new Date);
Sleep (1000);
Console.log (new Date);
Result
Wed Mar 2015 14:55:18 gmt+0800 (China Standard Time)
Wed Mar 2015 14:55:19 gmt+0800 (China Standard Time)
It's easy to use the same way that normal JavaScript functions are used.
The technical points that this article wants to share have been elaborated. But...... How does it compare with the method offered at the beginning? I do not have a screenshot, direct description of the result:
This is also validated by the fact that the method used in the addon approach is thread-suspended and there is no theoretical CPU footprint and memory changes. Then look at the JavaScript loop simulation of sleep, because the loop has been running, memory increased a little understandable, no big deal, and then look at the CPU 25%, it seems to be passable. Is that really the case? It's time to reveal the truth. I tested the CPU of the notebook computer is a dual-core four thread, combined with 25% CPU consumption ... Is there a thread in a dual-core four thread that is consumed by this sleep? In fact, I found that none of the threads were locked down during this period, but it was not the credit of JavaScript but the credit of Intel Hyper-Threading. Because said to be four threads, in fact, the essence is two processing core can only be two threads, but the CPU does a time slice cut on the trick. For example, the core cpu01 is divided into t0 and T2, assuming that in a tick after n tick (the dispatch cycle), the task will be assigned to T0, and then a tick at the back, the task will be assigned to T2. So from a relatively long time scale (relative to the scheduling cycle), a task on the t0 and T2 of the time is basically equivalent. So the scene is that the Nodejs process does not occupy T0 or T2 to 100%, but occupies 50% of the upper and lower respectively. Because of the relatively complex process scheduling of Windows, CPU consumption fluctuates a great amount. This can be predicted, if the dual-core dual-thread CPU to handle this script, CPU occupancy will rise to 50%, and a core card dead. If it is a single core CPU to deal with, the CPU will suddenly rise to 100%.
As if the CPU this paragraph is a bit more, hyper-threading Those are also guessing, you look at the good.