(v), the understanding of the blocking and non-blocking (pros and cons) of node. js

Source: Internet
Author: User

When writing a program, it takes a long time to finish a large function, but suddenly there is a need for a small function that needs to be completed first, then it pauses the big function, the first little function, this way is called blocking. As soon as the small function is done, continue to function bigger. This is the usual synchronous (synchronous) or blocking (Blocking) type.

Correspondingly, asynchronous (asynchronous) or non-blocking (non-blocking) does not adopt a blocking policy for all functions to be completed. When a thread encounters an operation, it does not wait for the operation to complete or return the data in a blocking manner, but simply sends the request to the operating system and proceeds to the next statement. When the operating system completes the operation, the thread that executes the action is notified as an event, and the thread handles the event at a particular time. In order to handle asynchrony, threads must have an event loop, constantly checking for unhandled events, and sequentially processing them.


In blocking mode, a thread can only handle one task, and the throughput must be multithreaded if it is to be improved. Instead of blocking mode, a thread is always performing a compute operation, and the CPU core utilization used by this thread is always 100%. In blocking mode, multithreading tends to improve system throughput because when one thread is blocked and other threads are working, multithreading can make the CPU resources not wasted by the threads in the blocking.

In non-blocking mode, threads are not blocked and are always using the CPU. The benefit of multithreading is simply to take advantage of more cores in the case of multicore CPUs, and node. JS uses a single-threaded, non-blocking event programming pattern to deliver the same benefits.


Suppose we have a function that can be divided into a computational part and a logical part, and the logical part takes up much more time than the calculation. If we use blocking, we have to turn on multiple threads to get high concurrency. When using asynchronous, a single-threaded process can be a competency.

Single-threaded event-driven asynchronous is better than traditional multithreaded blocking. In short, asynchronous means less multithreading overhead. For the operating system, the cost of creating a thread is very expensive, it needs to allocate memory, the scheduling, while the thread switch to perform memory paging, the CPU cache is emptied, switching back to the time to re-read information from memory. Of course, the disadvantage of asynchronous programming is that there is no difficulty in coding and debugging. But now there are many libraries (such as async) that specialize in solving asynchronous programming problems.

Here's an example (for the concept of modules and packages no longer speak, don't understand my third article about node. js)

Let's start by having the request handler return the information that needs to be displayed in the browser. The requesthandler.js file needs to be written as follows:

function Start () {Console.log ("Request handler ' start ' was called."); Return "Hello Start";}  function upload () {console.log ("Request handler ' upload ' was called."); Return "Hello Upload";} Exports.start = Start;exports.upload = upload;

Similarly, the route needs to return the information returned to it by the request handler to the server. The router.js file needs to be written as follows:

function route (handle, pathname) {Console.log ("about-to-route a request for" + pathname);  if (typeof handle[pathname] = = = ' function ') {return handle[pathname] ();    } else {Console.log ("No request handler found for" + pathname);  Return "404 Not Found"; }}exports.route = route;

As the code above shows, when the request has no "path", we also return some related error messages.
Finally, we need to write the Server.js file so that it can respond to the browser with the content returned by the request handler through the requested route, as follows:

var http = require ("http"), var url = require ("url"), function start (route, handle) {function onrequest (request, response)    {var pathname = Url.parse (request.url). Pathname;    Console.log ("Request for" + Pathname + "received.");    Response.writehead ($, {"Content-type": "Text/plain"});    var content = route (handle, pathname) Response.Write (content);  Response.End ();  } http.createserver (ONrequest). Listen (8888); Console.log ("Server has started."); Exports.start = start;


To introduce an object into the main file index.js:

var server = require ("./server"); var router = require ("./router"); var requesthandlers = require ("./requesthandlers"); var handle = {} handle["/"] = Requesthandlers.start; handle["/start"] = Requesthandlers.start; handle["/upload"] = requesthandlers.upload; Server.start (Router.route, handle);


If we run a refactoring application, everything will work fine: request
Http://localhost:8888/start, the browser outputs "Hello start", requesting
Http://localhost:8888/upload will output "Hello upload", and the request
Http://localhost:8888/foo will output "404 Not Found".
Okay, so where's the problem? Simply put, our application is "hung" when there is a need for a non-blocking operation in the future for a request handler.
Here's a detailed explanation.


As mentioned earlier, there is a problem when including non-blocking operations in the request handler. But before we say this, let's take a look at what a blocking operation is.
We look directly at what happens when a blocking operation is added to the request handler. Here, let's modify the start request handler and let it wait 10 seconds before returning
"Hello Start". Because there is no such thing as sleep () in JavaScript, only small programs can be used to simulate implementations.
Let's change the requesthandlers.js to the following form:

function Start () {Console.log ("Request handler ' start ' was called.");    function Sleep (milliSeconds) {var startTime = new Date (). GetTime ();  while (new Date (). GetTime () < StartTime + milliSeconds);  } sleep (10000); Return "Hello Start";} function upload () {console.log ("Request handler ' upload ' was called."); return "Hello upload";} Exports.start = Start;exports.upload = upload;

in the code above, node. js waits 10 seconds before returning to "Hello start" when the function start () is called.  When upload () is called, it returns as immediately as before.
(This is just simulated hibernation for 10 seconds.) )
Let's take a look at what changes have been made to our changes.
as usual, we need to restart the server first. To see the effect, we're going to do something relatively complicated (follow me): First, open two browser windows or tabs
page. Enter Http://localhost:8888/start in the address bar of the first browser window, but don't open it first! enter http://localhost:8888/upload in the address bar of the second browser window, again, don't open it! Next, do the following: press ENTER in the first window ("/start"), and then quickly switch to the second window ("/upload") and press ENTER.
Notice what happened:/start URL loading took 10 seconds, as we expected. However, the/upload URL actually took 10 seconds, and it was in the corresponding request handler and
There is no such operation as sleep ()!
What the hell is this? The reason is that start () contains blocking operations.  The image says, "It's blocking all the other processing work."
This is obviously a problem, as node has always said: "In node, everything is executed in parallel, except for the code."
This sentence means that node. js can still process tasks in parallel without adding additional external lines--node.js is single-threaded.  It implements parallel operations through event polling, which we should take advantage of--avoid blocking operations as much as possible and use non-blocking operations instead.
However, to use non-blocking operations, we need to use callbacks by passing functions as arguments to other functions that take time to do (say, hibernate for 10 seconds). For node. JS, this is how it handles: "Function () (note: This is the one that takes time to process), you continue to handle your business, I (node. js thread) waits for you, I continue to process the code behind you, Please provide a callbackfunction () (callback function), and I will call the callback function after you have finished processing.


Next, we'll describe a way to use non-blocking operations incorrectly.
This time we're going to experiment with the start request handler. Modify it to the following form:

var exec = require ("Child_process"). Exec;function start () {Console.log ("Request handler ' start ' was called.");  var content = "Empty";  EXEC ("Ls-lah", function (Error, stdout, stderr) {content = stdout;  }); return content;  }function upload () {console.log ("Request handler ' upload ' was called."); Return "Hello Upload";} Exports.start = Start;exports.upload = upload;

In the code above, we introduced a new node. js module, child_process.  It is used to achieve a simple and practical non-blocking operation: EXEC (). EXEC () it executes a shell command from node. js. In the example above, we use it to get all the files in the current directory ("Ls-lah"), and then output the file information to the browser when the/starturl is requested.

The above code creates a new variable content (the initial value is "empty"), executes the "Ls-lah" command, assigns the result to the content, and finally returns the content.

As usual, we started the server and then accessed "Http://localhost:8888/start".
It will then load a beautiful web page with the content "empty". This time, you may have guessed roughly, in non-blocking this piece played a role.   With exec (), we can perform very time-consuming operations without forcing our application to stop waiting for the operation. (If you want to prove this, you can replace "Ls-lah" with a more time-consuming operation like "find").

However, for the results of the browser display, our non-blocking operation is not good.
Next, let's fix the problem. In the process, let's take a look at why the current approach doesn't work.
The problem is that exec () uses a callback function for non-blocking work.
In our case, the callback function is the anonymous function passed to exec () as the second argument:

function (Error, stdout, stderr) {content = stdout;}

  is now at the root of the problem: our code is executed synchronously, which means that node. JS executes   return content  immediately after calling exec (); At this point, the content
is still " Empty "because the callback function passed to EXEC () has not yet been performed-because the operation of EXEC () is asynchronous. &NBSP;&NBSP,
Here "Ls-lah" operation is actually very fast. This is why the callback function is also executed quickly to  --  However, it is asynchronous anyway.   
to make the effect more obvious, we imagine a more time-consuming command:  "Find/", which takes about 1 minutes to execute on my machine, however, although in the request handler, I replace "Ls-lah" with "Find/" when open/ Start URL will still be able to get HTTP response immediately  --  obviously, when exec () executes in the background, node. JS itself continues to execute the following code. And here we assume that the callback function passed to exec () will only be called after the "Find/" command has finished executing.   
So how do we make it possible to display the list of files in the current directory to the user?   
Having learned this bad way to implement, let's look at how to get the request handler to respond to the browser request in the right way.  

Request response with non-blocking operation
I have just mentioned a phrase  --"the right Way". In fact, the usual "right way" is generally not easy.   
However, with node. JS, there is an implementation:  function passed. Let's take a look at how to implement it.   
So far our app has been able to return the request handler by applying the way values are passed between tiers (request handlers  ->  request Routing  ->  server) (the request The content that the
Manager eventually wants to display to the user) is passed to the HTTP server.   
Now we're using a new implementation: relative to the way the content is passed to the server, this time we adopt a way to "pass" the server to the content.   from a practical point of view,
Gets the response object (from the server's callback function ONrequest ()) through the request route to the request handler.   Subsequently, the handler can take a function on the object to respond to the
request.   
This is how it works, so let's step through it.   
starts with server.js first:    

var http = require ("http"), var url = require ("url"), function start (route, handle) {function onrequest (request, response)    {var pathname = Url.parse (request.url). Pathname;    Console.log ("Request for" + Pathname + "received.");  Route (handle, pathname, response);  } http.createserver (ONrequest). Listen (8888); Console.log ("Server has started."); Exports.start = start;

Instead of getting the return value from the route () function, this time we pass the response object as the third argument to the route () function, and we'll onrequest () in the handler
All the function notes about response are removed because we want this part of the work to be done by the route () function.
Here's a look at our router.js:

function route (handle, pathname, response) {Console.log ("about-route a request for" + pathname);  if (typeof handle[pathname] = = = ' function ') {Handle[pathname] (response);    } else {Console.log ("No request handler found for" + pathname);     Response.writehead (404, {"Content-type": "Text/plain"});    Response.Write ("404 Not Found");  Response.End (); }}exports.route = route;

The same pattern: instead of getting the return value from the request handler, this time the response object is passed directly.
If there is no corresponding request processor processing, we will return a "404" error directly. Finally, we will modify the Requesthandler.js to the following form:

var exec = require ("child_process") .exec;function  Start (response)  {  console.log ("request handler  ' Start '  was called.");   exec ("Ls -lah", function  (error, stdout, stderr)  {     response.writehead (200, {"Content-type":  "Text/plain"});     response.write (stdout);     response.end ();   }); Function upload (response)  {  console.log ("request handler  ' upload '  was  called. ");   response.writehead (200, {"Content-type":  "Text/plain"});   response.write (" Hello upload ");   response.end ();}  exports.start = start;exports.upload = upload; 

The

Our handler function needs to receive the response parameter in order to respond directly to the request. The     start handler does the request response in the anonymous callback function of exec (), while the upload
handler is still a simple reply to "Hello world", only this time using the response object.   
Then again we launch the app (node Index.js), and everything will work fine.    if you want to prove that the time-consuming operation in the/start handler does not block an
immediate response to the/upload request, you can modify the Requesthandlers.js to the following form:  

Var exec = require ("Child_process"). Exec;function start (response)  {   Console.log ("request handler  ' Start '  was called.");   exec ("find /",     { timeout: 10000, maxbuffer: 20000* 1024 },    function  (Error, stdout, stderr)  {       response.writehead (200, {"Content-type":  "Text/plain"});       response.write (stdout);       response.end ();     });}  function upload (response)  {  console.log ("request handler  ' upload '   Was called. ");   response.writehead (200, {"Content-type":  "Text/plain"});   response.write (" Hello upload ");   response.end ();} exports.start = start;exports.upload = upload;

In this way, it takes 10 seconds to load when the request Http://localhost:8888/start, and when the request Http://localhost:8888/upload, it responds immediately,
Even at this time, the/start response is still being processed.

Features of synchronous I/O and asynchronous I/O

650) this.width=650; "src=" Http://s3.51cto.com/wyfs02/M02/59/AD/wKioL1TcFV-QzSohAAHTUIJ5FEY753.jpg "title=" Image.png "alt=" Wkiol1tcfv-qzsohaahtuij5fey753.jpg "/>

This article is from "My dream Fly on the Sky" blog, please be sure to keep this source http://7915791.blog.51cto.com/7905791/1613929

(v), the understanding of the blocking and non-blocking (pros and cons) of node. js

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.