JavaScript có hỗ trợ đa luồng không

Javascript là một ngôn ngữ đơn luồng. Điều này có nghĩa là nó có một ngăn xếp cuộc gọi và một đống bộ nhớ. Như mong đợi, nó thực thi mã theo thứ tự và phải hoàn thành việc thực thi một đoạn mã trước khi chuyển sang phần tiếp theo. Nó đồng bộ, nhưng đôi khi có thể gây hại. Ví dụ: nếu một chức năng mất một lúc để thực thi hoặc phải chờ một thứ gì đó, thì nó sẽ đóng băng mọi thứ trong thời gian đó

Một ví dụ điển hình về điều này xảy ra là chức năng cảnh báo cửa sổ.

let flag = false
function doSomething[] {
  flag = true
  // More code [that doesn't change `flag`]...

  // We can be sure that `flag` here is true.
  // There's no way another code block could have changed
  // `flag` since this block is synchronous.
}
2

Bạn hoàn toàn không thể tương tác với trang web cho đến khi bạn nhấn OK và loại bỏ cảnh báo. bạn bị mắc kẹt

Vậy làm thế nào để chúng ta có được mã không đồng bộ với Javascript sau đó?

Chà, chúng ta có thể cảm ơn công cụ Javascript [V8, Spidermonkey, JavaScriptCore, v.v. ] cho điều đó, có API Web xử lý các tác vụ này trong nền. Ngăn xếp cuộc gọi nhận ra các chức năng của API Web và chuyển giao chúng cho trình duyệt xử lý. Sau khi các tác vụ đó được trình duyệt hoàn thành, chúng sẽ quay trở lại và được đẩy vào ngăn xếp dưới dạng gọi lại

Mở bảng điều khiển của bạn và nhập

let flag = false
function doSomething[] {
  flag = true
  // More code [that doesn't change `flag`]...

  // We can be sure that `flag` here is true.
  // There's no way another code block could have changed
  // `flag` since this block is synchronous.
}
3 rồi nhấn enter. Bạn sẽ thấy hầu hết mọi thứ mà API Web cung cấp. Điều này bao gồm những thứ như lệnh gọi ajax, trình xử lý sự kiện, API tìm nạp và setTimeout. Javascript sử dụng các ngôn ngữ lập trình cấp thấp như C++ để thực hiện những điều này đằng sau hậu trường

Hãy xem một ví dụ đơn giản, hãy chạy mã này trên bảng điều khiển của bạn

console.log["first"]
setTimeout[[] => {
    console.log["second"]
}, 1000]
console.log["third"]

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

Chúng ta đã nhận lại được gì?

first
third
undefined
second

Vào chế độ toàn màn hình Thoát chế độ toàn màn hình

Cảm thấy kỳ lạ, phải không?

let flag = false
function doSomething[] {
  flag = true
  // More code [that doesn't change `flag`]...

  // We can be sure that `flag` here is true.
  // There's no way another code block could have changed
  // `flag` since this block is synchronous.
}
4 nằm trong ngăn xếp đầu tiên, vì vậy nó sẽ được in. Tiếp theo, công cụ thông báo setTimeout không được xử lý bởi Javascript và chuyển nó sang WebAPI để được thực hiện không đồng bộ. Ngăn xếp cuộc gọi tiếp tục mà không cần quan tâm đến mã được chuyển giao cho API Web và
let flag = false
function doSomething[] {
  flag = true
  // More code [that doesn't change `flag`]...

  // We can be sure that `flag` here is true.
  // There's no way another code block could have changed
  // `flag` since this block is synchronous.
}
5 được in

Tiếp theo, vòng lặp sự kiện của công cụ Javascript bắt đầu, giống như một đứa trẻ hỏi "Chúng ta đã đến nơi chưa?" . Nó bắt đầu kích hoạt, chờ đợi các sự kiện được đẩy vào nó. Vì

let flag = false
function doSomething[] {
  flag = true
  // More code [that doesn't change `flag`]...

  // We can be sure that `flag` here is true.
  // There's no way another code block could have changed
  // `flag` since this block is synchronous.
}
6 chưa kết thúc, nên nó trả về
let flag = false
function doSomething[] {
  flag = true
  // More code [that doesn't change `flag`]...

  // We can be sure that `flag` here is true.
  // There's no way another code block could have changed
  // `flag` since this block is synchronous.
}
7, như mặc định, bởi vì nó chưa được cung cấp giá trị. Khi cuộc gọi lại cuối cùng thực hiện các lần truy cập, chúng tôi nhận được bản in
let flag = false
function doSomething[] {
  flag = true
  // More code [that doesn't change `flag`]...

  // We can be sure that `flag` here is true.
  // There's no way another code block could have changed
  // `flag` since this block is synchronous.
}
8

Có một trang web thực sự tốt giúp làm chậm tất cả điều này và cho thấy điều này đang xảy ra

http. // tiềm ẩn. com/loupe

Tôi khuyên bạn nên chơi xung quanh trong hộp cát này để giúp củng cố sự hiểu biết của bạn. Nó giúp tôi cảm nhận được mã không đồng bộ có thể hoạt động như thế nào với Javascript ở dạng đơn luồng

Ghi chú của biên tập viên. Bài đăng này đã được cập nhật vào ngày 18 tháng 1 năm 2022 để bao gồm một số thông tin mới về API Công nhân web và công nhân web nói chung, cải thiện và thêm định nghĩa về các thuật ngữ chính, đồng thời phản ánh sự hỗ trợ ổn định cho mô-đun

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
0.  

Kể từ khi phát hành Node. js v10. 5. 0, có sẵn một mô-đun

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
0 mới, đã ổn định kể từ Node. js v12 LTS

Chính xác mô-đun luồng Công nhân này là gì và tại sao chúng ta cần nó?

  • Lý do lịch sử đồng thời được triển khai trong JavaScript và Node. js
  • Các vấn đề chúng tôi có thể tìm thấy và các giải pháp hiện tại của họ
  • Tương lai của xử lý song song với Worker thread

Lịch sử của JavaScript đơn luồng

JavaScript được hình thành như một ngôn ngữ lập trình đơn luồng chạy trong trình duyệt. Đơn luồng có nghĩa là chỉ có một bộ hướng dẫn được thực thi bất kỳ lúc nào trong cùng một quy trình [trình duyệt, trong trường hợp này hoặc chỉ tab hiện tại trong các trình duyệt hiện đại]

Điều này giúp các nhà phát triển làm mọi thứ dễ dàng hơn vì JavaScript ban đầu là ngôn ngữ chỉ hữu ích để thêm tương tác vào trang web, xác thực biểu mẫu, v.v. — không có gì đòi hỏi sự phức tạp của đa luồng

Ryan Dahl coi giới hạn này là một cơ hội khi ông tạo ra Node. js. Anh ấy muốn triển khai nền tảng phía máy chủ dựa trên I/O không đồng bộ để tránh nhu cầu về luồng và giúp mọi việc dễ dàng hơn nhiều

Nhưng đồng thời có thể là một vấn đề rất khó giải quyết. Có nhiều luồng truy cập vào cùng một bộ nhớ có thể tạo ra các điều kiện tương tranh rất khó tái tạo và sửa chữa

là nút. js đơn luồng?

nút của chúng tôi. trên thực tế, các ứng dụng js chỉ là loại đơn luồng. Chúng tôi có thể chạy mọi thứ song song, nhưng chúng tôi không tạo chuỗi hoặc đồng bộ hóa chúng. Máy ảo và hệ điều hành chạy I/O song song cho chúng tôi và khi đến lúc gửi dữ liệu trở lại mã JavaScript của chúng tôi, đó là JavaScript chạy trong một luồng

Nói cách khác, mọi thứ chạy song song ngoại trừ mã JavaScript của chúng tôi. Các khối mã JavaScript đồng bộ luôn được chạy cùng một lúc

let flag = false
function doSomething[] {
  flag = true
  // More code [that doesn't change `flag`]...

  // We can be sure that `flag` here is true.
  // There's no way another code block could have changed
  // `flag` since this block is synchronous.
}

Điều này thật tuyệt nếu tất cả những gì chúng ta làm là I/O không đồng bộ. Mã của chúng tôi bao gồm các phần nhỏ của các khối đồng bộ chạy nhanh và truyền dữ liệu tới các tệp và luồng, vì vậy mã JavaScript của chúng tôi nhanh đến mức không chặn việc thực thi các đoạn mã JavaScript khác

Mất nhiều thời gian hơn để chờ đợi các sự kiện I/O xảy ra so với mã JavaScript đang được thực thi. Hãy xem điều này với một ví dụ nhanh

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]

Có thể truy vấn cơ sở dữ liệu này mất một phút, nhưng thông báo “Truy vấn đang chạy” sẽ được hiển thị ngay sau khi gọi truy vấn. Và chúng ta sẽ thấy thông báo “Xin chào” một giây sau khi gọi truy vấn bất kể truy vấn có còn chạy hay không

nút của chúng tôi. js chỉ gọi hàm và không chặn việc thực thi các đoạn mã khác. Nó sẽ được thông báo thông qua cuộc gọi lại khi truy vấn xong và chúng tôi sẽ nhận được kết quả

Sự cần thiết của các luồng để thực hiện các tác vụ sử dụng nhiều CPU

Điều gì xảy ra nếu chúng ta cần thực hiện các công việc đòi hỏi cường độ đồng bộ cao, chẳng hạn như thực hiện các phép tính phức tạp trong bộ nhớ trong một tập dữ liệu lớn?

Hãy tưởng tượng rằng một phép tính mất 10 giây. Nếu chúng tôi đang chạy một máy chủ web, điều đó có nghĩa là tất cả các yêu cầu khác sẽ bị chặn trong ít nhất 10 giây do tính toán đó. Đó là một thảm họa;

JavaScript và nút. js không được sử dụng cho các tác vụ liên quan đến CPU. Vì JavaScript là một luồng, điều này sẽ đóng băng giao diện người dùng trong trình duyệt và xếp hàng bất kỳ sự kiện I/O nào trong Node. js

Hơn 200 nghìn nhà phát triển sử dụng LogRocket để tạo ra trải nghiệm kỹ thuật số tốt hơn

Tìm hiểu thêm →

Quay trở lại ví dụ trước của chúng tôi, hãy tưởng tượng bây giờ chúng tôi có một truy vấn trả về vài nghìn kết quả và chúng tôi cần giải mã các giá trị trong mã JavaScript của mình

db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]

Chúng tôi sẽ nhận được kết quả trong cuộc gọi lại khi chúng khả dụng. Sau đó, không có mã JavaScript nào khác được thực thi cho đến khi cuộc gọi lại của chúng tôi kết thúc quá trình thực thi

Thông thường, như chúng tôi đã nói trước đây, mã tối thiểu và đủ nhanh, nhưng trong trường hợp này, chúng tôi có nhiều kết quả và chúng tôi cần thực hiện các tính toán nặng nề trên chúng. Quá trình này có thể mất vài giây và mọi hoạt động thực thi JavaScript khác sẽ được xếp hàng đợi trong thời gian đó, điều đó có nghĩa là chúng tôi có thể chặn tất cả người dùng của mình trong thời gian đó nếu chúng tôi đang chạy một máy chủ trong cùng một ứng dụng

Tại sao chúng ta sẽ không bao giờ có đa luồng trong JavaScript

Vì vậy, tại thời điểm này, nhiều người có thể nghĩ rằng giải pháp của chúng ta nên là thêm một mô-đun mới vào Node. js và cho phép chúng tôi tạo và đồng bộ hóa các chủ đề

Nhưng điều đó là không thể. Nếu chúng tôi thêm chủ đề vào JavaScript, thì chúng tôi đang thay đổi bản chất của ngôn ngữ. Chúng ta không thể chỉ thêm các luồng khi có sẵn một tập hợp các lớp hoặc chức năng mới - có lẽ chúng ta cần thay đổi ngôn ngữ để hỗ trợ đa luồng. Các ngôn ngữ hiện đang hỗ trợ nó có các từ khóa như

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
2 để cho phép các chủ đề hợp tác

Thật tiếc là chúng tôi không có cách hay để giải quyết trường hợp sử dụng này trong một nền tảng phía máy chủ trưởng thành như Node. js. Ví dụ, trong Java, thậm chí một số kiểu số không phải là nguyên tử;

Kết quả sẽ là, sau khi cả hai luồng đã truy cập biến, nó có một vài byte được thay đổi bởi một luồng và một vài byte được thay đổi bởi luồng khác — và do đó, sẽ không dẫn đến bất kỳ giá trị hợp lệ nào

Giải pháp ngây thơ. Tách mã đồng bộ

Nút. js sẽ không đánh giá khối mã tiếp theo trong hàng đợi sự kiện cho đến khi khối mã trước đó thực thi xong. Vì vậy, một điều đơn giản mà chúng ta có thể làm là chia mã của mình thành các khối mã đồng bộ nhỏ hơn và gọi

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
3 để thông báo cho Node. js chúng ta đã hoàn thành. Bằng cách này, nó có thể tiếp tục thực thi những thứ đang chờ xử lý trong hàng đợi;

Hãy xem cách chúng ta có thể cấu trúc lại một số mã từ ví dụ trước để tận dụng điều này. Hãy tưởng tượng chúng ta có một mảng lớn mà chúng ta muốn xử lý và mọi mục trong mảng đều yêu cầu xử lý nhiều CPU

const arr = [/*large array*/]
for [const item of arr] {
  // do heavy stuff for each item on the array
}
// code that runs after the whole array is executed

Như chúng tôi đã nói trước đây, nếu chúng tôi làm điều này, sẽ mất quá nhiều thời gian để xử lý toàn bộ mảng và phần còn lại của việc thực thi JavaScript sẽ bị chặn. Hãy chia phần này thành các phần nhỏ hơn và sử dụng

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
3

first
third
undefined
second
1

Bây giờ, chúng ta có thể xử lý 10 mục mỗi khi vòng lặp sự kiện chạy và gọi

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
3 để nếu có điều gì khác mà chương trình cần thực hiện, nó sẽ thực hiện ở giữa các khối 10 mục đó. Tôi đã thêm một
db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
6 để chứng minh chính xác điều đó

Các bài viết hay khác từ LogRocket

  • Đừng bỏ lỡ một khoảnh khắc nào với The Replay, một bản tin được tuyển chọn từ LogRocket
  • Tìm hiểu cách Galileo của LogRocket loại bỏ tiếng ồn để chủ động giải quyết các vấn đề trong ứng dụng của bạn
  • Sử dụng useEffect của React để tối ưu hóa hiệu suất ứng dụng của bạn
  • Chuyển đổi giữa nhiều phiên bản của Node
  • Khám phá cách tạo hoạt ảnh cho ứng dụng React của bạn với AnimXYZ
  • Khám phá Tauri, một khuôn khổ mới để xây dựng các tệp nhị phân
  • So sánh NestJS với. Thể hiện. js

Như bạn có thể thấy, mã trở nên phức tạp hơn. Và nhiều khi, thuật toán phức tạp hơn thế này rất nhiều, vì vậy thật khó để biết đặt

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
7 ở đâu để tìm được sự cân bằng tốt. Ngoài ra, mã bây giờ không đồng bộ và nếu chúng tôi phụ thuộc vào thư viện của bên thứ ba, chúng tôi có thể không chia được quá trình thực thi thành các phần nhỏ hơn

Chạy các quy trình song song trong nền, không có luồng

Vì vậy,

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
7 là đủ cho một số trường hợp sử dụng đơn giản, nhưng nó không phải là một giải pháp lý tưởng. Chúng ta có thể xử lý song song mà không cần chủ đề không?

Những gì chúng ta cần là một số loại xử lý nền, một cách chạy tác vụ với đầu vào có thể sử dụng bất kỳ lượng CPU nào và thời gian cần thiết để trả lại kết quả cho ứng dụng chính. Một cái gì đó như thế này

first
third
undefined
second
6

Thực tế là chúng ta đã có thể xử lý nền trong Node. js. chúng tôi có thể và thực hiện chính xác điều đó bằng cách sử dụng tính năng truyền tin nhắn, mà bạn có thể hình dung đơn giản như việc truyền tin nhắn từ quy trình này sang quy trình khác. Điều này đạt được các mục tiêu sau

  • Tiến trình chính có thể giao tiếp với tiến trình con bằng cách gửi và nhận các sự kiện
  • Không có bộ nhớ nào được chia sẻ
  • Tất cả dữ liệu được trao đổi đều được “nhân bản”, nghĩa là việc thay đổi dữ liệu ở một bên sẽ không thay đổi ở bên còn lại
  • Nếu chúng tôi không chia sẻ bộ nhớ, chúng tôi không có điều kiện chủng tộc và chúng tôi không cần chủ đề

Chà, chờ đã. Đây là một giải pháp, nhưng nó không phải là giải pháp lý tưởng. Việc rẽ nhánh một quy trình rất tốn kém và chậm — điều đó có nghĩa là chạy một máy ảo mới từ đầu và sử dụng nhiều bộ nhớ vì các quy trình không chia sẻ bộ nhớ

Chúng ta có thể sử dụng lại cùng một quy trình rẽ nhánh không?

  1. Bạn không thể chặn ứng dụng chính, nhưng quá trình rẽ nhánh sẽ chỉ có thể xử lý một tác vụ tại một thời điểm
  2. Nếu một tác vụ làm hỏng quy trình, nó sẽ khiến tất cả các tác vụ được gửi đến cùng một quy trình chưa hoàn thành

Nếu bạn có hai nhiệm vụ — một nhiệm vụ sẽ chiếm

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
9 và một nhiệm vụ sẽ chiếm
db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
0, theo thứ tự đó — không lý tưởng nếu bạn phải đợi
db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
9 để thực hiện nhiệm vụ thứ hai. Nó thậm chí còn kém lý tưởng hơn nếu nhiệm vụ đó không bao giờ được thực thi vì một quy trình khác đã cản trở nó

Vì chúng tôi đang chuyển đổi các quy trình, chúng tôi muốn tận dụng lợi thế của lịch trình hệ điều hành của chúng tôi và tất cả các lõi của máy của chúng tôi. Giống như cách bạn có thể nghe nhạc và duyệt internet cùng một lúc, bạn có thể rẽ nhánh hai quy trình và thực hiện song song tất cả các tác vụ

Để khắc phục những vấn đề này, chúng tôi cần nhiều nhánh, không chỉ một. Nhưng chúng tôi cần giới hạn số lượng quy trình rẽ nhánh vì mỗi quy trình sẽ có tất cả mã máy ảo được sao chép trong bộ nhớ, nghĩa là một vài MB cho mỗi quy trình và thời gian khởi động không hề nhỏ

Sử dụng
db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
2 để tổng hợp các chủ đề

Giống như với các kết nối cơ sở dữ liệu, chúng tôi cần một nhóm các quy trình đã sẵn sàng để sử dụng, chạy một tác vụ tại một thời điểm trong mỗi quy trình và sử dụng lại quy trình sau khi tác vụ kết thúc. Điều này có vẻ phức tạp để thực hiện và sẽ như vậy nếu chúng ta xây dựng nó từ đầu

Thay vào đó, hãy sử dụng

db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
3 để giúp chúng tôi

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
2

Vì vậy, vấn đề giải quyết?

Các luồng vẫn rất nhẹ về mặt tài nguyên so với các quy trình rẽ nhánh. Đây chính là lý do Worker thread ra đời

Chủ đề công nhân là gì?

Chủ đề công nhân có ngữ cảnh bị cô lập. Chúng trao đổi thông tin với tiến trình chính bằng cách truyền thông báo, vì vậy chúng tôi tránh được vấn đề điều kiện tranh đua mà các luồng thông thường mắc phải. Nhưng chúng sống trong cùng một quy trình, vì vậy chúng sử dụng ít bộ nhớ hơn

Bạn có thể chia sẻ bộ nhớ với Worker thread và chuyển các đối tượng

db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
4 hoặc
db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
5 dành riêng cho điều đó. Chỉ sử dụng chúng nếu bạn cần thực hiện các tác vụ sử dụng nhiều CPU với lượng dữ liệu lớn. Một số ví dụ về các tác vụ sử dụng nhiều CPU với Node worker được thảo luận trong bài viết này. Chúng cho phép bạn tránh phải tuần tự hóa dữ liệu

Sử dụng Worker thread cho nhiều tác vụ

Bạn có thể bắt đầu sử dụng mô-đun

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
0 ngay hôm nay nếu bạn chạy Node. js ≥ v10. 5. 0. Nếu bạn đang sử dụng bất kỳ phiên bản nào ≤ 11. 7. 0, tuy nhiên, bạn cần kích hoạt nó bằng cách sử dụng cờ
db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
7 khi gọi Node. js

Hãy nhớ rằng việc tạo Worker - mặc dù nó rẻ hơn rất nhiều so với việc tạo một quy trình - cũng có thể sử dụng quá nhiều tài nguyên tùy thuộc vào nhu cầu của bạn. Trong trường hợp đó, các tài liệu

Bạn có thể tìm kiếm một triển khai nhóm chung hoặc một triển khai cụ thể trong npm thay vì tạo triển khai nhóm của riêng bạn. Nút. js cung cấp để cung cấp tính năng theo dõi không đồng bộ thích hợp của nhóm công nhân

Hãy xem một ví dụ đơn giản. Trước tiên, chúng tôi sẽ triển khai tệp chính, tạo luồng Công nhân và cung cấp cho nó một số dữ liệu. API được điều khiển theo sự kiện, nhưng tôi sẽ đưa nó vào một lời hứa sẽ giải quyết trong tin nhắn đầu tiên nhận được từ Công nhân

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
7

Như bạn có thể thấy, điều này dễ dàng như chuyển tên tệp dưới dạng đối số và dữ liệu mà chúng tôi muốn Công nhân xử lý. Hãy nhớ rằng dữ liệu này được sao chép và không có trong bất kỳ bộ nhớ dùng chung nào

Khi chúng tôi hoàn thành, chúng tôi đợi Chuỗi công nhân gửi tin nhắn cho chúng tôi bằng cách lắng nghe sự kiện

db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
8. Thực hiện dịch vụ

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
9

Ở đây, chúng ta cần hai điều.

db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
9 mà ứng dụng chính đã gửi cho chúng tôi và cách trả lại thông tin cho ứng dụng chính. Điều này được thực hiện với
const arr = [/*large array*/]
for [const item of arr] {
  // do heavy stuff for each item on the array
}
// code that runs after the whole array is executed
0 có phương thức
const arr = [/*large array*/]
for [const item of arr] {
  // do heavy stuff for each item on the array
}
// code that runs after the whole array is executed
1 nơi chúng tôi sẽ chuyển kết quả xử lý của mình

Đó là nó. Đây là ví dụ đơn giản nhất, nhưng chúng ta vẫn có thể xây dựng những thứ phức tạp hơn — ví dụ: chúng ta có thể gửi nhiều thông báo từ Worker thread cho biết trạng thái thực thi nếu chúng ta cần cung cấp phản hồi

Hoặc chúng tôi có thể gửi một phần kết quả. Hãy tưởng tượng rằng bạn đang xử lý hàng ngàn hình ảnh. Có thể bạn muốn gửi tin nhắn cho mỗi hình ảnh được xử lý, nhưng bạn không muốn đợi cho đến khi tất cả chúng được xử lý

Để chạy ví dụ, hãy nhớ sử dụng cờ

db.findAll['SELECT ...', function[err, results] {
  if [err] return console.error[err]


  // Heavy computation and many results
  for [const encrypted of results] {
    const plainText = decrypt[encrypted]
    console.log[plainText]
  }
}]
7 nếu bạn đang sử dụng bất kỳ phiên bản nào trước Node. js 11. 7

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
4

Để biết thêm thông tin, hãy xem

const arr = [/*large array*/]
for [const item of arr] {
  // do heavy stuff for each item on the array
}
// code that runs after the whole array is executed
3

API công nhân web là gì?

Có thể bạn đã nghe nói về Web Worker API. API khác với

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
0 vì nhu cầu và điều kiện kỹ thuật khác nhau, nhưng chúng có thể giải quyết các vấn đề tương tự trong thời gian chạy trình duyệt

Web Worker API hoàn thiện hơn và dành cho các trình duyệt hiện đại. Nó có thể hữu ích nếu bạn đang khai thác tiền điện tử, nén/giải nén, thao tác hình ảnh, thị giác máy tính [e. g. , nhận dạng khuôn mặt], v.v. trong ứng dụng web của bạn

giới thiệu. phố tiệc tùng

Công nhân web cũng có thể được sử dụng để chạy tập lệnh của bên thứ ba. Chạy tập lệnh nặng từ luồng chính có thể gây ra sự cố UX trên trang web của bạn, điều này không lý tưởng, nhưng việc chạy tập lệnh ngoài luồng chính có thể tạo ra sự cố vì chúng tôi không có quyền truy cập trực tiếp vào API luồng chính như

const arr = [/*large array*/]
for [const item of arr] {
  // do heavy stuff for each item on the array
}
// code that runs after the whole array is executed
5,

Đây là nơi Partytown xuất hiện. Partytown là gói 6kB được tải chậm giúp bạn giải quyết vấn đề được đề cập. Các gói bên thứ ba của bạn sẽ chạy như mong đợi mà không ảnh hưởng đến luồng chính. Nếu bạn muốn thử điều này, hãy xem bài đăng khác của chúng tôi khám phá thư viện hoặc xem tài liệu của họ để thảo luận sâu hơn

Sự kết luận

db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
0 là một mô-đun thú vị và hữu ích nếu bạn cần thực hiện các tác vụ sử dụng nhiều CPU trong Nút của mình. ứng dụng js. Chúng cung cấp hành vi giống như các luồng mà không chia sẻ bộ nhớ và do đó, tránh được các điều kiện chủng tộc tiềm ẩn mà các luồng giới thiệu. Kể từ khi mô-đun
db.findOne['SELECT .. LIMIT 1', function[err, result] {
  if [err] return console.error[err]
  console.log[result]
}]
console.log['Running query']
setTimeout[function[] {
  console.log['Hey there']
}, 1000]
0 trở nên ổn định trong Node. js v12 LTS, bạn nên yên tâm sử dụng nó trong các ứng dụng cấp sản xuất

là đa

js chính nó là đa luồng và cung cấp các luồng ẩn thông qua thư viện libuv, xử lý các hoạt động I/O như đọc tệp từ đĩa hoặc yêu cầu mạng. Thông qua việc sử dụng các luồng ẩn, Node. js cung cấp các phương thức không đồng bộ cho phép mã của bạn thực hiện các yêu cầu I/O mà không chặn luồng chính.

JavaScript đơn luồng hay đa luồng?

Trong bối cảnh lập trình, Parallelism là việc sử dụng nhiều luồng trong một hệ điều hành. Các quy trình có thể chạy cùng lúc bất kể thứ tự thực hiện. Tuy nhiên, JavaScript là luồng đơn và chỉ một dòng mã có thể được thực thi tại bất kỳ thời điểm nào.

Tại sao JavaScript không thể đa luồng?

JS trong trình duyệt không hỗ trợ đa luồng trong vòng lặp sự kiện vì không cần thiết cho 99. 999% trang web . Vòng lặp sự kiện xử lý mọi thứ liền mạch. Đối với các ứng dụng còn lại, nhà phát triển có thể sử dụng nhân viên web. Công nhân web là một phương tiện đơn giản để nội dung web chạy các tập lệnh trong các luồng nền.

Làm cách nào để tạo đa luồng JavaScript?

Thiết lập trình xử lý web & đa luồng cho JavaScript .
Bước 1. Tạo một thư mục dự án và thêm chỉ mục. html trong thư mục gốc của nó. .
Bước 2. Hãy thêm mã JavaScript của chúng tôi vào hai tệp riêng biệt, chính. js và công nhân. js trong cùng một thư mục. .
Bước 3. Về một số giải thích về những gì vừa xảy ra

Chủ Đề