Giết tiến trình con nodejs

Yes, before Node. js 11 chúng ta có thể sử dụng mô-đun cụm. Nhưng nếu server chỉ có một nhân duy nhất thì phải làm sao?

Thật may là ở phiên bản Node. js 11 chúng ta có module worker_thread cứu tinh. Mô-đun này cho phép chúng ta sinh ra nhiều luồng chạy trên lõi đơn. Chúng ta cũng có thể sử dụng mô-đun này với cờ –experimental-worker ở Node. js 10 nhưng mình khuyến mãi là không nên

Một ví dụ đơn giản về cấu hình

Giả sử chúng ta cần tạo ra một tệp chưa 1 triệu người dùng với tên đầy đủ của họ.
Mình đã tìm được một kho lưu trữ Github cũng cấp cho họ một mảng danh sách các tên của họ để phục vụ cho ví dụ này. https. //github. com/dominictarr/tên ngẫu nhiên

Đầu tiên hãy tạo một dự án mới với cấu trúc như sau

[root]
|
+------ main.js
|
+------ [data]
|       |
|       +-- first_name.json
|       +-- last_name.json
|       +-- middle_name.json
|
+------ [utils]
|       |
|       +-- index.js
|
|
+------ [output]
        |
        +-- data.txt

Bắt đầu với main.js

const fs = require("fs-extra");
const {
    getRandomIndex
} = require("./utils")
const firstName = require("./data/first_name.json");
const middleName = require("./data/middle_name.json");
const lastName = require("./data/last_name.json");

const limit = 1000000;
const outputFile = `${__dirname}/output/data.txt`;

(async () => {
    for (let i = 0; i < limit; i++) {
        const data = [firstName, middleName, lastName]
            .map(getRandomIndex)
            .concat("\n")
            .join(" ");
        await fs.appendFile(outputFile, data);
    }
})();

Như các bạn có thể thấy, chúng ta sử dụng gói fs-extra. Nó xử lý tương tự như mô-đun fs, nhưng sẽ trả về lời hứa cho từng chức năng

Nó giải quyết một vấn đề lớn đối với hệ thống, đó là dung lượng bộ nhớ. Sự thật là nếu chúng ta cố gắng mở quá nhiều tệp với Node. js, nó sẽ sinh ra lỗi và hủy tiến trình chính. Bởi vì nó không thể xử lý quá nhiều tệp mở cùng một lúc (tràn bộ nhớ)

Trong vòng lặpfor của chúng ta,

const fs = require("fs-extra");
const {
    getRandomIndex
} = require("./utils")
const firstName = require("./data/first_name.json");
const middleName = require("./data/middle_name.json");
const lastName = require("./data/last_name.json");

const limit = 1000000;
const outputFile = `${__dirname}/output/data.txt`;

(async () => {
    for (let i = 0; i < limit; i++) {
        const data = [firstName, middleName, lastName]
            .map(getRandomIndex)
            .concat("\n")
            .join(" ");
        await fs.appendFile(outputFile, data);
    }
})();
0 sẽ dừng vòng lặp cho đến khi nhiệm vụ kết thúc. Bằng cách này, chúng tôi sẽ chỉ xử lý một tệp cho mỗi lần lặp

function getRandomIndex(array) {
    return array[Math.floor(Math.random() * array.length)];
}

module.exports = {
    getRandomIndex
}

Ở đây chúng ta chỉ lấy các giá trị ngẫu nhiên từ bất kỳ mảng nào. Sử dụng để trộn ngẫu nhiên tên họ

Chạy đoạn mã trên máy tính xách tay cá nhân (2016 MacBook Pro, 2,7 GHz Intel Core i7, 16GB RAM) mất khoảng 3 phút và 32 giây để hoàn tất

Cố gắng sử dụng Node. js worker thread để xem hiệu suất có khác biệt không nhé

Triển khai đa luồng với Node. js

Để phát triển đa luồng cho chương trình này, chúng ta cần thay đổi một số vị trí trong mã. Bắt đầu với main.js tệp

const {
    Worker
} = requirer("worker_threads");
const logUpdate = require("log-update");

const limit = 1000000;
const threads = 10;
const namesPerThread = limit / threads;
const outputFile = `${__dirname}/output/data.txt`;
let names = [...Array(threads)].fill(0);

for (let i = 0; i < threads; i++) {
    const port = new Worker(require.resolve("./worker.js"), {
        workerData: {
            namesPerThread,
            outputFile
        }

    });
    port.on("message", (data) => handleMessage(data, i));
    port.on("error", (e) => console.log(e));
    port.on("exit", (code) => console.log(`Exit code: ${code}`));
}

function handleMessage(_, index) {
    names[index]++;
    logUpdate(names.map((status, i) => `Thread ${i}: ${status}`).join("\n"));
}
  • Đầu tiên chúng ta cần nhập 
    const fs = require("fs-extra");
    const {
        getRandomIndex
    } = require("./utils")
    const firstName = require("./data/first_name.json");
    const middleName = require("./data/middle_name.json");
    const lastName = require("./data/last_name.json");
    
    const limit = 1000000;
    const outputFile = `${__dirname}/output/data.txt`;
    
    (async () => {
        for (let i = 0; i < limit; i++) {
            const data = [firstName, middleName, lastName]
                .map(getRandomIndex)
                .concat("\n")
                .join(" ");
            await fs.appendFile(outputFile, data);
        }
    })();
    2 lớp từ mô-đun
    const fs = require("fs-extra");
    const {
        getRandomIndex
    } = require("./utils")
    const firstName = require("./data/first_name.json");
    const middleName = require("./data/middle_name.json");
    const lastName = require("./data/last_name.json");
    
    const limit = 1000000;
    const outputFile = `${__dirname}/output/data.txt`;
    
    (async () => {
        for (let i = 0; i < limit; i++) {
            const data = [firstName, middleName, lastName]
                .map(getRandomIndex)
                .concat("\n")
                .join(" ");
            await fs.appendFile(outputFile, data);
        }
    })();
    0. This job allow them ta sinh ra worker bất cứ lúc nào
  • Sau đó chúng ta cần thiết lập số lượng các chủ đề cần được sinh ra. Trong trường hợp này mình quyết định sinh ra 10 chủ đề
  • Chúng ta cần tính toán có bao nhiêu tên cần được tạo ra trên mỗi luồng. Chỉ cần chia tổng số tên hiện tại cho tổng số chủ đề
  • Với mỗi chủ đề, chúng ta cần sinh ra một
    const fs = require("fs-extra");
    const {
        getRandomIndex
    } = require("./utils")
    const firstName = require("./data/first_name.json");
    const middleName = require("./data/middle_name.json");
    const lastName = require("./data/last_name.json");
    
    const limit = 1000000;
    const outputFile = `${__dirname}/output/data.txt`;
    
    (async () => {
        for (let i = 0; i < limit; i++) {
            const data = [firstName, middleName, lastName]
                .map(getRandomIndex)
                .concat("\n")
                .join(" ");
            await fs.appendFile(outputFile, data);
        }
    })();
    2 mới. Mã sẽ được đặt trong tệp
    const fs = require("fs-extra");
    const {
        getRandomIndex
    } = require("./utils")
    const firstName = require("./data/first_name.json");
    const middleName = require("./data/middle_name.json");
    const lastName = require("./data/last_name.json");
    
    const limit = 1000000;
    const outputFile = `${__dirname}/output/data.txt`;
    
    (async () => {
        for (let i = 0; i < limit; i++) {
            const data = [firstName, middleName, lastName]
                .map(getRandomIndex)
                .concat("\n")
                .join(" ");
            await fs.appendFile(outputFile, data);
        }
    })();
    2
  • Chúng ta gửi một trọng tải đến
    const fs = require("fs-extra");
    const {
        getRandomIndex
    } = require("./utils")
    const firstName = require("./data/first_name.json");
    const middleName = require("./data/middle_name.json");
    const lastName = require("./data/last_name.json");
    
    const limit = 1000000;
    const outputFile = `${__dirname}/output/data.txt`;
    
    (async () => {
        for (let i = 0; i < limit; i++) {
            const data = [firstName, middleName, lastName]
                .map(getRandomIndex)
                .concat("\n")
                .join(" ");
            await fs.appendFile(outputFile, data);
        }
    })();
    2 mới để biết số tên cần được tạo ra và nơi để lưu chúng

Vui lòng xem cách mà 

const fs = require("fs-extra");
const {
    getRandomIndex
} = require("./utils")
const firstName = require("./data/first_name.json");
const middleName = require("./data/middle_name.json");
const lastName = require("./data/last_name.json");

const limit = 1000000;
const outputFile = `${__dirname}/output/data.txt`;

(async () => {
    for (let i = 0; i < limit; i++) {
        const data = [firstName, middleName, lastName]
            .map(getRandomIndex)
            .concat("\n")
            .join(" ");
        await fs.appendFile(outputFile, data);
    }
})();
2  hoạt động

const {
    getRandomIndex
} = require("./utils");
const {
    parentPort,
    workerData
} = require("worker_threads")
const fs = require("fs-extra");

const firstName = require("./data/first_name.json");
const middleName = reguire("./data/middle_name.json");
const lastName = require("./data/last_name.json");
const {
    namesPerThread,
    outputFile
} = workerData;

~function async() {
    for (let i = 0; i < namesPerThread; i++) {
        const data = [firstName, middleName, lastName]
            .map(getRandomIndex)
            .concat("\n")
            .join(" ");
        await fs.appendFile(outputFile, data);
        parentPort.postMessage(data);
    }
}()

Về cơ bản nó giống như mã của main.js. Tuy nhiên, mỗi khi chúng ta lưu một tên mới, chúng ta sẽ gửi trả về chủ đề chính để theo dõi những gì diễn ra bên trong các chủ đề phụ

Kết quả như thế nào? . Nhanh hơn 37% so với khi chỉ sử dụng một chủ đề

Những ứng dụng khác sử dụng đa luồng với Node. js

Worker Threads là một giải pháp tuyệt vời khi bạn cần thực hiện một nhiệm vụ chuyên sâu với CPU. Chúng tôi làm cho các hoạt động liên quan đến hệ thống tập tin nhanh hơn và giúp ích rất nhiều khi bạn cần thực hiện bất kỳ loại hoạt động đồng thời nào. Điều tuyệt vời nhất, như mình đã nói trước đây, chúng cũng hoạt động trên các máy chủ đơn lẻ, vì vậy xin chúc mừng một hiệu suất tốt hơn trên bất kỳ máy chủ nào

Mình thường sử dụng Worker Threads trong các nhiệm vụ upload hàng loạt, nơi mình phải kiểm tra hàng triệu người dùng và lưu trữ dữ liệu của họ vào cơ sở dữ liệu. Áp dụng cách tiếp cận đa luồng, thao tác nhanh hơn khoảng 10 lần so với thao tác đơn luồng trên cùng một nhiệm vụ

Mình cũng sử dụng Worker Threads để xử lý ảnh. Công việc cần làm là xây dựng các hình thu nhỏ (với kích thước khác nhau) từ một hình ảnh và sử dụng đa luồng giúp tiết kiệm điện rất nhiều thời gian cũng như tài nguyên của máy chủ

Kết luận

Từ những ứng dụng nêu trên, các bạn có thể thấy được module Worker Thread có thể giúp chúng ta rất nhiều trong việc nâng cao hiệu suất, tiết kiệm tài nguyên và giúp công việc trở nên thật sự hiệu quả

Hy vọng sau bài hướng dẫn này, các bạn có thể áp dụng đa luồng vào dự án Node. js của mình