Nút. js là một trong những công nghệ được ưa thích nhất hiện có để xây dựng các ứng dụng web thời gian thực do tính chất không chặn, hướng sự kiện và đơn luồng của nó. Nút. js được xây dựng với mục đích phát triển các ứng dụng có thể xử lý hiệu quả các hoạt động chuyên sâu I/O
Tại sao chúng ta cần xử lý song song?
Một trong những thành phần quan trọng nhất trong kiến trúc của Node là libuv. libuv là một thư viện dựa trên C++ giúp thực thi không đồng bộ các hoạt động dựa trên I/O theo cách không chặn. Nó cũng cung cấp một giao diện được gọi là Vòng lặp sự kiện, lấy mã được thực thi từ ngăn xếp cuộc gọi và thực thi nó. Do tính chất đơn luồng, Vòng lặp sự kiện chỉ thực hiện một việc tại một thời điểm
Khi Vòng lặp sự kiện gặp mã phải được thực thi không đồng bộ [e. g. , truy cập hệ thống tệp, thực hiện cuộc gọi mạng và các hoạt động I/O khác], thay vì tự thực thi mã, mã này ủy quyền mã đó cho một nhóm luồng và chuyển sang thực thi phần còn lại của chương trình. Sau đó, các luồng sẽ thực thi song song mã không đồng bộ và trả lại một sự kiện cho Vòng lặp sự kiện sau khi hoàn thành
[email protected]", "gender": "Male", "ip_address": "163.213.59.129" }
Chương trình của chúng tôi sẽ đọc từng tệp JSON, phân tích cú pháp và chuyển đổi nó thành đầu ra XML
Đọc/ghi tệp là các hoạt động I/O và Nút. js sẽ xử lý chúng một cách không đồng bộ
Tuy nhiên, phân tích cú pháp JSON và chuyển đổi nó thành XML sẽ là một hoạt động đòi hỏi CPU vì chúng tôi có một số lượng lớn các đối tượng JSON lớn
kịch bản thực hiện
Ghi chú. Trong tất cả các trường hợp, thời gian đọc nội dung từ tệp JSON không được thêm vào thời gian thực hiện. Chúng tôi đã sử dụng chức năng để tính toán thời gian thực hiện. Để cân bằng lỗi, chúng tôi sẽ chạy mỗi kịch bản 5 lần và lấy thời gian trung bình làm thời gian thực hiện
Tình huống 1 - Thực thi đồng bộ không có luồng worker
Ở đây, chúng tôi phân tích cú pháp và chuyển đổi nội dung JSON theo cách đồng bộ mà không cần sử dụng worker thread
⏰ Thời gian thực hiện trung bình. 1036 mili giây
Kịch bản 2 - Thực thi không đồng bộ với một luồng công nhân
Ở đây, chúng tôi phân tích cú pháp và chuyển đổi nội dung JSON theo cách không đồng bộ bằng một luồng công nhân
Chúng tôi sẽ sử dụng mô-đun worker_threads tích hợp từ Node. js để quản lý Worker Threads
⏰ Thời gian thực hiện trung bình. 1146 mili giây
Trong trường hợp này, chúng tôi thấy thời gian thực hiện tăng nhẹ. Mặc dù hiện tại hoạt động yêu cầu CPU được chạy trên một luồng riêng biệt, công nhân cũng sẽ mất một khoảng thời gian tương tự để thực hiện hoạt động. Bản thân việc tạo một luồng công nhân mới là một hoạt động tốn kém và do đó chúng tôi thấy thời gian thực hiện tăng lên
Thực thi không đồng bộ một thao tác CPU trên một luồng đơn lẻ có thể có lợi nếu bạn có một số phần khác của chương trình có thể thực thi song song trong luồng chính. Vì trong trường hợp sử dụng của chúng tôi, chúng tôi không có bất kỳ hướng dẫn nào được thực hiện sau thao tác chuyển đổi, luồng chính sẽ đợi cho đến khi luồng con kết thúc quá trình thực hiện
Tuy nhiên, chúng ta có thể chia hoạt động chuyên sâu của CPU [chuyển đổi JSON sang XML] thành nhiều phần và gán từng phần cho một luồng riêng biệt. Chúng ta có thể gán từng phần cho các luồng công nhân riêng biệt hoặc chúng ta có thể gán một phần cho luồng công nhân và phần còn lại chúng ta có thể để luồng chính xử lý. Dù bằng cách nào, chúng tôi sẽ có nhiều hơn một luồng hoạt động song song trên hoạt động. Hiện tại, giả sử chúng ta muốn giữ luồng chính miễn phí cho một số tác vụ khác và thực hiện theo cách tiếp cận thực thi trong hai luồng công nhân
Mặc dù chúng ta có thể đạt được trường hợp sử dụng trên bằng cách tạo một mảng các luồng công nhân, nhưng sẽ tốt hơn nếu sử dụng thư viện tổng hợp luồng công nhân sẽ đơn giản hóa và trừu tượng hóa việc quản lý các luồng công nhân cho chúng ta
Tình huống 3 - Thực thi song song với hai luồng công nhân
Ở đây, chúng tôi phân tích cú pháp và chuyển đổi JSON thành hai phần. Một nửa nội dung được chuyển đổi [50 tệp JSON], chúng tôi sẽ gán cho một luồng công nhân và nửa nội dung còn lại, chúng tôi sẽ gán cho một luồng công nhân khác. Để quản lý worker thread, chúng ta sẽ sử dụng thư viện tổng hợp có tên là piscina
⏰ Thời gian thực hiện trung bình. 687 mili giây
Sử dụng hai luồng công nhân, chúng ta có thể thấy thời gian thực hiện giảm đáng kể so với các kịch bản trước đó. Có nhiều hơn một luồng xử lý song song các phần của hoạt động chuyên sâu của CPU làm tăng đáng kể hiệu suất chương trình của chúng tôi
Tiếp theo, chúng ta hãy thử chia nhỏ thao tác trên hơn nữa để chúng ta có thể sử dụng nhiều luồng hơn và xem tác động đến hiệu suất
Dưới đây, bạn có thể tìm thấy thời gian thực hiện mà tôi đã ghi lại với số lượng luồng công nhân khác nhau bằng thư viện piscina
Không. của Worker Threads 2345678 Thời gian thực hiện [tính bằng mili giây]687577476502527558609Từ dữ liệu trên, chúng ta có thể thấy rằng thời gian thực hiện tiếp tục giảm cho đến khi có 4 luồng công nhân và sau đó, nó bắt đầu tăng dần. Nhiều luồng hơn cũng có nghĩa là nhiều thời gian hơn để tạo luồng, giao tiếp giữa các luồng và chuyển ngữ cảnh
ghi chú cuối cùng
Việc sử dụng các luồng công nhân để xử lý song song các hoạt động chuyên sâu của CPU sẽ mang lại những cải tiến hiệu suất đáng kể. Tuy nhiên, điều này không có nghĩa là nhiều luồng hơn tương ứng trực tiếp với hiệu suất tốt hơn
Chúng ta cũng có thể sử dụng ArrayBuffer và SharedArrayBuffer để thực hiện truyền hoặc chia sẻ bộ nhớ giữa các luồng để thực thi hiệu quả hơn
Xem xét tất cả những điều trên, chúng ta cần quyết định số luồng tối ưu nhất để mang lại hiệu suất tốt nhất cho trường hợp sử dụng