Home > Web Front-end > JS Tutorial > body text

Detailed explanation of fiber (fiber) library in nodejs_node.js

WBOY
Release: 2016-05-16 16:07:51
Original
1618 people have browsed it

fiber/fiber

In the operating system, in addition to processes and threads, there is also a type of fiber (fiber, also called coroutine) that is rarely used. Fibers are often compared with threads. For the operating system, they are both lightweight running states. Fibers are generally considered to be more lightweight and have less overhead than threads. The difference is that fibers are created by threads or fibers, and fiber scheduling is completely controlled by user code. For the system kernel, it is a non-preemptive scheduling method. Fibers realize cooperative multi-tasking. ; Threads and processes are scheduled by the kernel and implement preemptive multitasking according to priority. In addition, the system kernel does not know the specific running status of fibers, and the use of fibers is actually relatively independent of the operating system.

In node, single thread is only for javascript, and its bottom layer is actually full of multi-threads. If you need to implement multi-threading in JavaScript, a common approach is to write a C addon to bypass the single-thread mechanism of JavaScript. However, this method increases the difficulty and cost of development and debugging. Like many other scripting languages, we can also introduce the concept of fibers into node.

node-fibers

The node-fibers library provides fiber functions for node. The multi-threading test has not produced ideal results, but it has a significant effect in converting asynchronous to synchronous, and may also be valuable in reducing node call stacks and infinite recursion. This document mainly introduces how to use the node-fibers library and asynchronous to synchronous conversion.

Install

node-fibers are written in C language. Directly downloading the source code requires compilation. Usually, you can install it directly with npm:

Copy code The code is as follows:

npm install fibers

Usage of fibers library

API

1.Fiber(fn)/ new Fiber(fn):

Create a fiber, which can be used as a constructor or called as an ordinary function. For example:

Copy code The code is as follows:

function fibo(n) {
Return n > 1 ? fibo(n - 1) fibo(n - 2) : 1;
}
Fiber(function () {
console.log(fibo(40));
});

When run() is called, the fiber starts and allocates a new stack for fn. fn will run on this new stack until fn has a return value or yield() is called. After fn returns or calls yield(), the stack is reset. When run() is called again, the fiber will be started again, and fn runs in the stack allocated for the first time.

2.Fiber.current:

Get the current fiber and operate on it. If you specify a variable to be associated with it, be sure to ensure that this fiber can be released, otherwise V8's garbage collection mechanism will always ignore this part of the memory, causing memory leaks.

3.Fiber.yield(param):

This function has been mentioned in the previous description. The yield() method is used to interrupt the fiber, similar to return to a certain extent. Once yield() is executed, subsequent code in this Fiber will have no chance to execute, for example:

Copy code The code is as follows:

var fiber = Fiber(function () {
console.log("Fiber Start");
Fiber.yield();
console.log("Fiber Stop");
}).run();
// Output: "Fiber Start"

After execution, only "Fiber Start" will be output, and the latter output command will not be executed. If a parameter is passed to yield(), then this parameter is used as the return value of run().

Copy code The code is as follows:

var fiber = Fiber(function () {
Fiber.yield("success");
}).run();
console.log(fiber); // -> "success"

4.Fiber.prototype.run(param):

This method is already very familiar. There are two tenses for calling run() mentioned before, one is when the Fiber is not started, and the other is when the Fiber is yielded. The behavior of run() is not the same in these two tenses.
When Fiber is not started, run() accepts an argument and passes it to fn as its argument. When Fiber handles the yielding state, run() accepts a parameter and uses it as the return value of yield(). fn will not run from the beginning, but will continue running from the point of interruption. The relationship between the parameters and return values ​​of fn, yield, and run can be explained through the following small example:

Copy code The code is as follows:

var Fiber = require('fibers');
var fiber = Fiber(function (a) {
console.log("First call run:");
console.log("fn parameter is: " a);
var b = Fiber.yield("yield");
console.log("Second call run:");
console.log("fn parameter is: " a);
console.log("yield return value is: " b);
Return "return";
});
// First run run()
var c=fiber.run("One");
//Run run()
for the second time var d=fiber.run("Two");
console.log("Calling yield, run returns: " c);
console.log("fn operation is completed, run returns: " d);

The output is as follows:

Copy code The code is as follows:

/*
The first time you call run:
The fn parameter is: One
Call run:
for the second time The fn parameter is: One
The return value of yield is: Two
Call yield, run returns: yield
fn is completed and run returns: return
*/

From the above example, it is obvious that the usage of yield is quite different from the current JavaScript syntax. The yield keyword has been implemented in other languages ​​(C#, Python, etc.) as an interrupt for iterators. You might as well implement an iterator on node and experience the use of yield in detail. Let’s take the Fibonacci sequence at the beginning as an example:

Copy code The code is as follows:

var fiboGenerator = function () {
var a = 0, b = 0;
while (true) {
If (a == 0) {
            a = 1;
Fiber.yield(a);
         } else {
              b = a;
                b == a ? a = 1 : a = b - a;
Fiber.yield(b);
}
}
}
var f = new Fiber(fiboGenerator);
f.next = f.run;
for (var i = 0; i < 10; i ) {
console.log(f.next());
}

The output is:

Copy code The code is as follows:

/*
1
1
2
3
5
8
13
21
34
55
*/

There are two issues to pay attention to. First, yield is said to be a method, more like a keyword. Unlike run, yield does not need to rely on a Fiber instance, while run does. If you call run inside Fiber, you must use: Fiber.current.run(); secondly, yield itself is a reserved keyword of JavaScript. It is not sure if and when it will be enabled, so the code may face changes in the future. .

5.Fiber.prototype.reset():

We already know that Fiber may have different tenses, which will also affect the behavior of run. The reset method returns to the initial state no matter what state Fiber processes. Subsequent execution of run will rerun fn.

6.Fiber.prototype.throwInto(Exception):

Essentially, throwInto will throw the exception passed to it and use the exception information as the return value of run. If the exception it throws is not handled in Fiber, the exception will continue to bubble up. Regardless of whether the exception is handled or not, it will force yield and interrupt Fiber.

Usage of future library

It is not always reasonable to use Fiber directly in node, because the API of Fiber is really simple. In actual use, it will inevitably produce repetitive and lengthy code, which is not conducive to maintenance. It is recommended to add a layer of abstraction between node and Fiber to allow Fiber to work better. The future library provides such an abstraction. The future library or any level of abstraction may not be perfect. No one is right or wrong, only what is applicable or not. For example, the future library provides us with a simple API that can complete the work of asynchronous to synchronous, but it cannot do anything to encapsulate the generator (similar to the Fibonacci sequence generator above).

The future library does not need to be downloaded and installed separately. It is already included in the fibers library. When using it, you only need var future=require('fibers/future').

API

1.Function.prototype.future():

Added future method to Function type, converting function into a "funture-function".

Copy code The code is as follows:

var futureFun = function power(a) {
Return a * a;
}.future();
console.log(futureFun(10).wait());

Actually the power method is executed within Fibel. However, the existing version of future has bugs, and there is no official official explanation. If you need to use this function, please delete lines 339 and 350 of future.js.

2.new Future()

Constructor of Future object, detailed below.

3.Future.wrap(fn, idx)

The wrap method encapsulates the asynchronous to synchronous operation and is the most valuable method to us in the future library. fn represents the function that needs to be converted, idx represents the number of parameters accepted by fn, and its callback method is considered to be the last parameter (the formulation of the API here is quite controversial. Some people tend to pass the position where the callback should be. Fortunately, the wrap method is relatively simple and can be It is easier to modify the code). You can understand the usage of wrap by looking at an example:

Copy code The code is as follows:

var readFileSync = Future.wrap(require("fs").readFile);
Fiber(function () {
var html = readFileSync("./1.txt").wait().toString();
console.log(html);
}).run();

From this example, we can see that Fiber asynchronous to synchronous conversion is indeed very effective. Except for the additional step .wait() in the syntax, the other fs.readFileSync methods already provided by fs are the same.

4.Future.wait(futures):

This method has been seen many times before. As the name suggests, its function is to wait for results. If you want to wait for the result of a future instance, just call futureInstance.wait() directly; if you need to wait for the result of a series of future instances, call Future.wait(futuresArray). It should be noted that in the second usage, if an error occurs when a future instance is running, the wait method will not throw an error, but we can use the get() method to directly obtain the running result.

5.Future.prototype.get():

The usage of get() is very similar to the first method of wait(). The difference is that get() returns the result immediately. If the data is not ready, get() will throw an error.

6.Future.prototype.resolve(param1,param2):

The wrap method above always gives people the impression that the future is actually swallowing the callback function of the asynchronous method and directly returns the asynchronous result. In fact, future also provides a solution for setting callback functions through the resolve method. resolve accepts up to two parameters. If only one parameter is passed in, future will think that a node-style callback function is passed, such as the following example:

Copy code The code is as follows:

futureInstance.resolve(함수(err, data) {
만약 (오류) {
           오류를 던집니다.
} 그 밖의 {
console.log(data.toString());
}
});

두 개의 매개변수가 전달되면 오류와 데이터가 별도로 처리된다는 의미입니다.

코드 복사 코드는 다음과 같습니다.

futureInstance.resolve(함수 (err) {
던지기 오류;
}, 함수(데이터) {
console.log(data.toString());
});

또한 future는 Resolve의 호출 시점을 구분하지 않습니다. 데이터가 준비되지 않은 경우 콜백 함수가 대기열에 푸시되고 Resolver() 메서드에 의해 균일하게 예약됩니다. 그렇지 않으면 데이터를 직접 가져옵니다. 콜백 함수가 즉시 실행됩니다.

7.Future.prototype.isResolved():

작업이 수행되었는지 여부를 나타내는 부울 값을 반환합니다.

8.Future.prototype.proxy(futureInstance):

프록시 메소드는 본질적으로 해결 메소드의 래퍼인 미래 인스턴스에 대한 프록시를 제공합니다. 실제로 한 인스턴스의 콜백 메소드를 다른 인스턴스의 콜백 실행자로 사용합니다. 예:

코드 복사 코드는 다음과 같습니다.

var target = 새로운 Future;
target.resolve(함수 (err, data) {
console.log(데이터)
});
var ProxyFun = 함수(숫자, cb) {
cb(null, num * num);
};
섬유(함수 () {
var 프록시 = Future.wrap(proxyFun)(10);
Proxy.proxy(대상);
}).run(); // 100을 출력

프록시가 실행되더라도 결국에는 대상의 콜백 함수가 실행되고, 프록시의 실행 결과에 따라 대상의 콜백 함수가 구동됩니다. 이 프록시 방법은 실제 응용 프로그램에서 큰 역할을 할 수 있지만 아직 깊이 생각해 보지 않았습니다.

9.Future.prototype.return(값):

10.Future.prototype.throw(오류):

11.Future.prototype.resolver():

12.Future.prototype.detach():

위 4가지 API의 경우 다른 API에 비해 실제 사용 시나리오나 기능은 상대적으로 평균적이라고 생각합니다. return과 throw는 모두 리졸버 메서드에 의해 예약됩니다. 이 세 가지 메서드는 매우 중요하며 일반적인 향후 사용 프로세스에서 자동으로 작동합니다. 그러나 별도로 사용하는 구체적인 시나리오를 파악하지 못했기 때문에 소개할 방법이 없습니다. 상세히. Detach 방식은 Resolve 방식의 단순화된 버전으로만 간주할 수 있으므로 도입할 필요는 없습니다.

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!