Là I / O không chặn thực sự nhanh hơn I / O chặn đa luồng? Làm sao?


117

Tôi đã tìm kiếm trên web một số chi tiết kỹ thuật về việc chặn I / O và không chặn I / O và tôi thấy một số người nói rằng I / O không chặn sẽ nhanh hơn chặn I / O. Ví dụ trong tài liệu này .

Nếu tôi sử dụng chặn I / O, thì dĩ nhiên chuỗi hiện đang bị chặn không thể làm gì khác ... Bởi vì nó bị chặn. Nhưng ngay khi một luồng bắt đầu bị chặn, HĐH có thể chuyển sang luồng khác và không chuyển trở lại cho đến khi có một việc cần làm đối với luồng bị chặn. Vì vậy, miễn là có một luồng khác trên hệ thống cần CPU và không bị chặn, thì không nên có thêm thời gian nhàn rỗi của CPU so với cách tiếp cận không chặn dựa trên sự kiện, phải không?

Bên cạnh việc giảm thời gian CPU không hoạt động, tôi còn thấy một tùy chọn nữa để tăng số lượng tác vụ mà máy tính có thể thực hiện trong một khung thời gian nhất định: Giảm chi phí được giới thiệu bằng cách chuyển đổi luồng. Nhưng làm thế nào điều này có thể được thực hiện? Và chi phí có đủ lớn để hiển thị các hiệu ứng có thể đo lường được không? Đây là một ý tưởng về cách tôi có thể hình dung nó hoạt động:

  1. Để tải nội dung của tệp, một ứng dụng ủy thác nhiệm vụ này cho khung i / o dựa trên sự kiện, chuyển một hàm gọi lại cùng với tên tệp
  2. Khung sự kiện ủy quyền cho hệ điều hành, chương trình điều khiển DMA của đĩa cứng để ghi tệp trực tiếp vào bộ nhớ
  3. Khung sự kiện cho phép mã tiếp tục chạy.
  4. Sau khi hoàn thành sao chép đĩa vào bộ nhớ, bộ điều khiển DMA gây ra gián đoạn.
  5. Trình xử lý ngắt của hệ điều hành thông báo khung i / o dựa trên sự kiện về tệp được tải hoàn toàn vào bộ nhớ. sao làm được vậy? Sử dụng tín hiệu ??
  6. Mã hiện đang chạy trong khung i / o sự kiện kết thúc.
  7. Khung i / o dựa trên sự kiện kiểm tra hàng đợi của nó và xem thông báo của hệ điều hành từ bước 5 và thực hiện cuộc gọi lại trong bước 1.

nó vận hành như vậy sao? Nếu không, nó hoạt động như thế nào? Điều đó có nghĩa là hệ thống sự kiện có thể hoạt động mà không cần phải chạm vào ngăn xếp một cách rõ ràng (chẳng hạn như một bộ lập lịch thực sự cần sao lưu ngăn xếp và sao chép ngăn xếp của một luồng khác vào bộ nhớ trong khi chuyển đổi các luồng)? Điều này thực sự tiết kiệm bao nhiêu thời gian? Nó có nhiều hơn nữa không?


5
Câu trả lời ngắn gọn: đó là chi tiết về chi phí cho mỗi luồng kết nối. không chặn io cho phép một người tránh có một luồng trên mỗi kết nối.
Dan D.

10
Chặn IO rất tốn kém trên một hệ thống mà bạn không thể tạo nhiều luồng như các kết nối tồn tại. Trên JVM, bạn có thể tạo một số nghìn luồng, nhưng nếu bạn có hơn 100.000 kết nối thì sao? Vì vậy, bạn phải bám vào một giải pháp không đồng bộ. Tuy nhiên, có những ngôn ngữ mà các luồng không đắt tiền (ví dụ như các luồng màu xanh lá cây) như trong Go / Erlang / Rust, nơi không có vấn đề gì khi có 100.000 luồng. Khi số lượng chủ đề có thể lớn, tôi tin rằng việc chặn IO mang lại thời gian phản hồi nhanh hơn. Nhưng đó là điều tôi cũng sẽ phải hỏi các chuyên gia liệu điều đó có đúng trong thực tế không.
OlliP

@OliverPlow, tôi cũng nghĩ vậy, vì chặn IO thường có nghĩa là chúng ta để hệ thống xử lý "quản lý song song", thay vì tự mình sử dụng hàng đợi nhiệm vụ và như vậy.
Pacerier

1
@DanD., Và nếu chi phí có các luồng bằng với tổng phí thực hiện IO không chặn thì sao? (thường đúng trong trường hợp chủ đề màu xanh lá cây)
Pacerier

"Sao chép ngăn xếp" không xảy ra. Chủ đề khác nhau có ngăn xếp của họ tại các địa chỉ khác nhau. Mỗi luồng có con trỏ ngăn xếp riêng, cùng với các thanh ghi khác. Một chuyển đổi ngữ cảnh lưu / khôi phục chỉ trạng thái kiến ​​trúc (bao gồm tất cả các thanh ghi), nhưng không phải bộ nhớ. Giữa các luồng trong cùng một tiến trình, kernel thậm chí không phải thay đổi các bảng trang.
Peter Cordes

Câu trả lời:


44

Ưu điểm lớn nhất của I / O không chặn hoặc không đồng bộ là luồng của bạn có thể tiếp tục công việc song song. Tất nhiên bạn có thể đạt được điều này cũng bằng cách sử dụng một chủ đề bổ sung. Như bạn đã nói về hiệu suất tổng thể (hệ thống) tốt nhất, tôi đoán sẽ tốt hơn nếu sử dụng I / O không đồng bộ và không phải nhiều luồng (do đó giảm chuyển đổi luồng).

Hãy xem xét các triển khai có thể có của chương trình máy chủ mạng sẽ xử lý song song 1000 máy khách được kết nối:

  1. Một luồng trên mỗi kết nối (có thể chặn I / O, nhưng cũng có thể không chặn I / O).
    Mỗi luồng yêu cầu tài nguyên bộ nhớ (cũng là bộ nhớ kernel!), Đó là một bất lợi. Và mỗi luồng bổ sung có nghĩa là nhiều công việc hơn cho bộ lập lịch.
  2. Một chủ đề cho tất cả các kết nối.
    Điều này mất tải từ hệ thống vì chúng tôi có ít luồng hơn. Nhưng nó cũng ngăn bạn sử dụng toàn bộ hiệu suất của máy, vì cuối cùng bạn có thể điều khiển một bộ xử lý đến 100% và để tất cả các bộ xử lý khác không hoạt động.
  3. Một vài luồng trong đó mỗi luồng xử lý một số kết nối.
    Điều này mất tải từ hệ thống vì có ít luồng hơn. Và nó có thể sử dụng tất cả các bộ xử lý có sẵn. Trên Windows phương pháp này được API Pool Pool hỗ trợ .

Tất nhiên có nhiều chủ đề không phải là một vấn đề. Như bạn có thể nhận ra tôi đã chọn khá nhiều kết nối / chủ đề. Tôi nghi ngờ rằng bạn sẽ thấy bất kỳ sự khác biệt nào giữa ba triển khai có thể có nếu chúng ta chỉ nói về một tá chủ đề (đây cũng là những gì Raymond Chen gợi ý trên bài đăng trên blog của MSDN Windows có giới hạn 2000 luồng cho mỗi quy trình không? ).

Trên Windows sử dụng I / O tệp không có bộ đệm có nghĩa là ghi phải có kích thước là bội số của kích thước trang. Tôi chưa thử nghiệm nó, nhưng có vẻ như điều này cũng có thể ảnh hưởng tích cực đến hiệu suất ghi đối với việc ghi đồng bộ và không đồng bộ được đệm.

Các bước 1 đến 7 bạn mô tả cho một ý tưởng tốt về cách thức hoạt động của nó. Trên Windows, hệ điều hành sẽ thông báo cho bạn về việc hoàn thành I / O không đồng bộ ( WriteFileOVERLAPPEDcấu trúc) bằng cách sử dụng một sự kiện hoặc gọi lại. Chức năng gọi lại sẽ chỉ được gọi là ví dụ như khi bạn gọi đang WaitForMultipleObjectsExbAlertablecác thiết lập để true.

Một số đọc thêm trên web:


Từ quan điểm web kiến ​​thức phổ biến (Internet, ý kiến ​​từ các chuyên gia) cho thấy rằng tăng đáng kể tối đa. số lượng luồng yêu cầu là một điều tồi tệ trong việc chặn IO (khiến việc xử lý các yêu cầu thậm chí chậm hơn) do tăng bộ nhớ và thời gian chuyển ngữ cảnh, nhưng, Async IO có làm điều tương tự khi trì hoãn công việc sang luồng khác không? Có, bạn có thể phục vụ nhiều yêu cầu hơn bây giờ nhưng có cùng số lượng chủ đề trong nền .. lợi ích thực sự của việc đó là gì?
JavierJ

1
@JavierJ Dường như bạn tin rằng nếu n luồng làm tập tin async thì một luồng n khác sẽ được tạo để thực hiện chặn tệp IO? Đây không phải là sự thật. HĐH có hỗ trợ IO không đồng bộ và không cần chặn khi chờ IO hoàn tất. Nó có thể xếp hàng các yêu cầu IO và nếu xảy ra gián đoạn phần cứng (ví dụ DMA), nó có thể đánh dấu yêu cầu là xong và đặt một sự kiện báo hiệu luồng của người gọi. Ngay cả khi một luồng bổ sung được yêu cầu, HĐH sẽ có thể sử dụng luồng đó cho nhiều yêu cầu IO từ nhiều luồng.
Werner Henze

Cảm ơn, có ý nghĩa liên quan đến tệp hỗ trợ IO của hệ điều hành IO nhưng khi tôi viết mã để triển khai thực tế điều này (từ quan điểm web), hãy nói với Java Servlet 3.0 NIO Tôi vẫn thấy một luồng cho yêu cầu và luồng nền ( async) lặp để đọc một tập tin, cơ sở dữ liệu hoặc bất cứ điều gì.
JavierJ

1
@piyushGidel Tôi viết lại câu trả lời của mình. Tôi hy vọng nó rõ ràng hơn bây giờ.
Werner Henze

1
Trên Windows sử dụng I / O tệp không đồng bộ có nghĩa là ghi phải có kích thước là bội số của kích thước trang. - không, nó không. Bạn đang nghĩ về I / O không có bộ đệm. (Chúng thường được sử dụng cùng nhau, nhưng chúng không phải như vậy.)
Harry Johnston

29

I / O bao gồm nhiều loại hoạt động như đọc và ghi dữ liệu từ ổ cứng, truy cập tài nguyên mạng, gọi dịch vụ web hoặc truy xuất dữ liệu từ cơ sở dữ liệu. Tùy thuộc vào nền tảng và loại hoạt động, I / O không đồng bộ thường sẽ tận dụng mọi hỗ trợ phần cứng hoặc hệ thống cấp thấp để thực hiện thao tác. Điều này có nghĩa là nó sẽ được thực hiện với ít tác động nhất có thể đến CPU.

Ở cấp độ ứng dụng, I / O không đồng bộ ngăn các luồng phải chờ các hoạt động I / O hoàn tất. Ngay sau khi một hoạt động I / O không đồng bộ được bắt đầu, nó sẽ giải phóng chuỗi mà nó được khởi chạy và một cuộc gọi lại được đăng ký. Khi hoạt động hoàn tất, cuộc gọi lại được xếp hàng để thực hiện trên luồng có sẵn đầu tiên.

Nếu thao tác I / O được thực thi đồng bộ, nó sẽ giữ luồng chạy của nó không làm gì cho đến khi hoàn thành thao tác. Thời gian chạy không biết khi nào hoạt động I / O hoàn thành, do đó, nó sẽ định kỳ cung cấp một số thời gian CPU cho luồng chờ, thời gian CPU có thể được sử dụng bởi các luồng khác có hoạt động ràng buộc CPU thực tế để thực hiện.

Vì vậy, như @ user1629468 đã đề cập, I / O không đồng bộ không cung cấp hiệu suất tốt hơn mà là khả năng mở rộng tốt hơn. Điều này là hiển nhiên khi chạy trong các ngữ cảnh có số lượng luồng có hạn, giống như trường hợp của các ứng dụng web. Ứng dụng web thường sử dụng một nhóm luồng mà từ đó chúng gán các luồng cho mỗi yêu cầu. Nếu các yêu cầu bị chặn trong các hoạt động I / O chạy dài, có nguy cơ làm cạn kiệt nhóm web và làm cho ứng dụng web bị đóng băng hoặc chậm phản hồi.

Một điều tôi nhận thấy là I / O không đồng bộ không phải là lựa chọn tốt nhất khi xử lý các hoạt động I / O rất nhanh. Trong trường hợp đó, lợi ích của việc không giữ một luồng bận trong khi chờ thao tác I / O hoàn thành là không quan trọng lắm và thực tế là hoạt động được bắt đầu trên một luồng và nó được hoàn thành trên một luồng khác để thêm chi phí cho việc thực hiện chung.

Bạn có thể đọc một nghiên cứu chi tiết hơn mà tôi đã thực hiện gần đây về chủ đề I / O không đồng bộ so với đa luồng ở đây .


Tôi tự hỏi liệu có đáng để phân biệt giữa các thao tác I / O dự kiến ​​sẽ hoàn thành hay không và những thứ có thể không [ví dụ: "lấy ký tự tiếp theo đến trên cổng nối tiếp", trong trường hợp thiết bị từ xa có thể hoặc không gửi bất cứ điều gì]. Nếu một hoạt động I / O dự kiến ​​sẽ hoàn thành trong một thời gian hợp lý, người ta có thể trì hoãn việc dọn sạch các tài nguyên liên quan cho đến khi hoạt động hoàn tất. Tuy nhiên, nếu hoạt động có thể không bao giờ hoàn thành, sự chậm trễ như vậy sẽ không hợp lý.
supercat

@supercat kịch bản bạn đang mô tả được sử dụng trong các ứng dụng và thư viện cấp thấp hơn. Máy chủ đang dựa vào nó, vì họ liên tục chờ kết nối đến. I / O Async như được mô tả ở trên không thể phù hợp với kịch bản này vì nó dựa trên việc bắt đầu một hoạt động cụ thể và đăng ký một cuộc gọi lại để hoàn thành nó. Trong trường hợp bạn đang mô tả, bạn cần đăng ký gọi lại về một sự kiện hệ thống và xử lý mọi thông báo. Bạn đang liên tục xử lý đầu vào thay vì thực hiện các hoạt động. Như đã nói, điều này thường được thực hiện ở mức thấp, hầu như không bao giờ trong ứng dụng của bạn.
Florin Dumitrescu

Mẫu này khá phổ biến với các ứng dụng đi kèm với nhiều loại phần cứng khác nhau. Các cổng nối tiếp không phổ biến như trước đây, nhưng các chip USB mô phỏng các cổng nối tiếp khá phổ biến trong thiết kế phần cứng chuyên dụng. Các ký tự từ những thứ đó được xử lý ở cấp ứng dụng, vì HĐH sẽ không có cách nào biết rằng một chuỗi các ký tự đầu vào có nghĩa là một ngăn kéo tiền mặt đã được mở và một thông báo sẽ được gửi đi đâu đó.
supercat

Tôi không nghĩ phần chi phí CPU để chặn IO là chính xác: khi ở trạng thái chặn, một luồng kích hoạt chặn IO được HĐH chờ đợi và không mất thời gian CPU cho đến khi IO hoàn thành, chỉ sau đó hệ điều hành (thông báo bằng ngắt) tiếp tục chuỗi bị chặn. Những gì bạn mô tả (chờ đợi bận rộn bằng cách bỏ phiếu dài) không phải là cách chặn IO được thực hiện trong hầu hết mọi thời gian chạy / trình biên dịch.
Lifu Huang

4

Lý do chính để sử dụng AIO là cho khả năng mở rộng. Khi xem trong bối cảnh của một vài chủ đề, lợi ích không rõ ràng. Nhưng khi hệ thống mở rộng tới 1000 luồng, AIO sẽ cung cấp hiệu năng tốt hơn nhiều. Thông báo trước là thư viện AIO không nên đưa ra các nút thắt cổ chai.


4

Để giả định sự cải thiện tốc độ do bất kỳ hình thức đa điện toán nào, bạn phải cho rằng nhiều tác vụ dựa trên CPU đang được thực thi đồng thời trên nhiều tài nguyên máy tính (nói chung là lõi xử lý) hoặc không phải tất cả các tác vụ đều phụ thuộc vào việc sử dụng đồng thời cùng một tài nguyên - nghĩa là, một số tác vụ có thể phụ thuộc vào một thành phần con của hệ thống (lưu trữ đĩa, trong khi một số tác vụ phụ thuộc vào một tác vụ khác (nhận thông tin liên lạc từ thiết bị ngoại vi) và các tác vụ khác có thể yêu cầu sử dụng lõi xử lý.

Kịch bản đầu tiên thường được gọi là lập trình "song song". Kịch bản thứ hai thường được gọi là lập trình "đồng thời" hoặc "không đồng bộ", mặc dù "đồng thời" đôi khi cũng được sử dụng để chỉ trường hợp chỉ cho phép một hệ điều hành xen kẽ thực thi nhiều tác vụ, bất kể việc thực thi đó có phải thực hiện không đặt ser seri hoặc nếu nhiều tài nguyên có thể được sử dụng để đạt được thực thi song song. Trong trường hợp sau này, "đồng thời" thường đề cập đến cách thực thi được viết trong chương trình, thay vì từ quan điểm của tính đồng thời thực tế của thực thi tác vụ.

Thật dễ dàng để nói về tất cả những điều này với các giả định ngầm. Ví dụ: một số người nhanh chóng đưa ra yêu cầu, chẳng hạn như "I / O không đồng bộ sẽ nhanh hơn I / O đa luồng". Yêu cầu này là không rõ ràng vì nhiều lý do. Đầu tiên, đó có thể là trường hợp một số khung I / O không đồng bộ nhất định được triển khai chính xác với đa luồng, trong trường hợp chúng là một trong cùng một trường hợp và không có nghĩa gì để nói một khái niệm "nhanh hơn" khái niệm kia .

Thứ hai, ngay cả trong trường hợp khi có một triển khai đơn luồng của khung không đồng bộ (như vòng lặp sự kiện đơn luồng), bạn vẫn phải đưa ra giả định về việc vòng lặp đó đang làm gì. Ví dụ, một điều ngớ ngẩn bạn có thể làm với một vòng lặp sự kiện đơn luồng là yêu cầu nó hoàn thành không đồng bộ hai tác vụ hoàn toàn bị ràng buộc CPU khác nhau. Nếu bạn đã làm điều này trên một máy chỉ có lõi xử lý đơn lý tưởng hóa (bỏ qua tối ưu hóa phần cứng hiện đại) thì thực hiện nhiệm vụ này "không đồng bộ" sẽ không thực sự khác biệt so với thực hiện với hai luồng được quản lý độc lập hoặc chỉ với một quy trình đơn độc - - sự khác biệt có thể đến từ chuyển đổi ngữ cảnh luồng hoặc tối ưu hóa lịch trình hệ điều hành, nhưng nếu cả hai tác vụ đều đi đến CPU thì nó cũng tương tự trong cả hai trường hợp.

Thật hữu ích khi tưởng tượng rất nhiều trường hợp góc bất thường hoặc ngu ngốc mà bạn có thể gặp phải.

"Không đồng bộ" không nhất thiết phải đồng thời, ví dụ như trên: bạn "không đồng bộ" thực thi hai tác vụ gắn với CPU trên một máy có chính xác một lõi bộ xử lý.

Việc thực thi đa luồng không nhất thiết phải đồng thời: bạn sinh ra hai luồng trên một máy có lõi xử lý duy nhất hoặc yêu cầu hai luồng để có được bất kỳ loại tài nguyên khan hiếm nào khác (hãy tưởng tượng, một cơ sở dữ liệu mạng chỉ có thể thiết lập một luồng kết nối tại một thời điểm). Việc thực thi của các luồng có thể được xen kẽ tuy nhiên bộ lập lịch của hệ điều hành thấy phù hợp, nhưng tổng thời gian chạy của chúng không thể giảm (và sẽ được tăng từ chuyển đổi ngữ cảnh luồng) trên một lõi (hoặc nói chung hơn, nếu bạn sinh ra nhiều luồng hơn mức có lõi để chạy chúng, hoặc có nhiều luồng yêu cầu tài nguyên hơn những gì tài nguyên có thể duy trì). Điều này cũng đi cho đa xử lý là tốt.

Vì vậy, I / O không đồng bộ và đa luồng không phải cung cấp bất kỳ hiệu suất nào về thời gian chạy. Họ thậm chí có thể làm mọi thứ chậm lại.

Tuy nhiên, nếu bạn xác định trường hợp sử dụng cụ thể, giống như một chương trình cụ thể vừa thực hiện cuộc gọi mạng để truy xuất dữ liệu từ tài nguyên được kết nối mạng như cơ sở dữ liệu từ xa và cũng thực hiện một số tính toán gắn với CPU cục bộ, thì bạn có thể bắt đầu lý do về sự khác biệt hiệu năng giữa hai phương pháp đưa ra một giả định cụ thể về phần cứng.

Các câu hỏi cần đặt ra: Tôi cần bao nhiêu bước tính toán và có bao nhiêu hệ thống tài nguyên độc lập để thực hiện chúng? Có tập hợp các bước tính toán yêu cầu sử dụng các thành phần phụ hệ thống độc lập và có thể hưởng lợi từ việc thực hiện đồng thời không? Tôi có bao nhiêu lõi xử lý và chi phí sử dụng nhiều bộ xử lý hoặc luồng để hoàn thành các tác vụ trên các lõi riêng biệt là gì?

Nếu nhiệm vụ của bạn chủ yếu dựa vào các hệ thống con độc lập, thì một giải pháp không đồng bộ có thể tốt. Nếu số lượng luồng cần thiết để xử lý nó sẽ lớn, thì việc chuyển đổi ngữ cảnh trở nên không tầm thường đối với hệ điều hành, thì một giải pháp không đồng bộ một luồng có thể tốt hơn.

Bất cứ khi nào các tác vụ bị ràng buộc bởi cùng một tài nguyên (ví dụ: nhiều nhu cầu truy cập đồng thời cùng một mạng hoặc tài nguyên cục bộ), thì đa luồng có thể sẽ đưa ra chi phí không đạt yêu cầu và trong khi không đồng bộ đơn luồng có thể giới thiệu ít chi phí hơn, trong một tài nguyên đó tình hình hạn chế nó cũng không thể tạo ra một tốc độ. Trong trường hợp như vậy, tùy chọn duy nhất (nếu bạn muốn tăng tốc) là tạo sẵn nhiều bản sao của tài nguyên đó (ví dụ: nhiều lõi xử lý nếu tài nguyên khan hiếm là CPU; cơ sở dữ liệu tốt hơn hỗ trợ nhiều kết nối đồng thời hơn nếu tài nguyên khan hiếm là một cơ sở dữ liệu giới hạn kết nối, v.v.).

Một cách khác để nói là: cho phép hệ điều hành xen kẽ việc sử dụng một tài nguyên cho hai tác vụ không thể nhanh hơn việc chỉ để một tác vụ sử dụng tài nguyên trong khi chờ đợi, sau đó để nhiệm vụ thứ hai kết thúc một cách an toàn. Hơn nữa, chi phí lập lịch của xen kẽ có nghĩa là trong bất kỳ tình huống thực tế, nó thực sự tạo ra một sự chậm lại. Sẽ không có vấn đề gì nếu việc sử dụng xen kẽ xảy ra đối với CPU, tài nguyên mạng, tài nguyên bộ nhớ, thiết bị ngoại vi hoặc bất kỳ tài nguyên hệ thống nào khác.


2

Một triển khai có thể của I / O không chặn chính xác như những gì bạn đã nói, với một chuỗi các luồng nền có chức năng chặn I / O và thông báo cho luồng của người khởi tạo I / O thông qua một số cơ chế gọi lại. Trên thực tế, đây là cách mô-đun AIO trong glibc hoạt động. Dưới đây là một số chi tiết mơ hồ về việc thực hiện.

Mặc dù đây là một giải pháp tốt, khá dễ mang theo (miễn là bạn có các luồng), HĐH thường có khả năng phục vụ I / O không chặn hiệu quả hơn. Bài viết Wikipedia này liệt kê các triển khai có thể bên cạnh nhóm chủ đề.


2

Tôi hiện đang trong quá trình triển khai async io trên nền tảng nhúng bằng cách sử dụng protothreads. Không chặn io tạo ra sự khác biệt giữa chạy ở tốc độ 16000fps và 160fps. Lợi ích lớn nhất của việc không chặn io là bạn có thể cấu trúc mã của mình để làm những việc khác trong khi phần cứng làm việc đó. Ngay cả việc khởi tạo các thiết bị có thể được thực hiện song song.

Martin


1

Trong Node, nhiều luồng đang được khởi chạy, nhưng đó là một lớp trong thời gian chạy C ++.

"Vì vậy, NodeJS là một luồng đơn, nhưng đây là một nửa sự thật, thực ra nó là một sự kiện và một luồng với các nhân viên nền. Vòng lặp sự kiện chính là một luồng nhưng hầu hết các công việc I / O chạy trên các luồng riêng biệt, bởi vì các API I / O trong Node.js không đồng bộ / không chặn theo thiết kế, để phù hợp với vòng lặp sự kiện. "

https://codeburst.io/how-node-js-single-thread-mechanism-work-under Hiểu-event-global-in-nodejs-30f7440b0ea

"Node.js không chặn, điều đó có nghĩa là tất cả các hàm (gọi lại) được ủy quyền cho vòng lặp sự kiện và chúng (hoặc có thể) được thực thi bởi các luồng khác nhau. Điều đó được xử lý bởi thời gian chạy của Node.js."

https://itnext.io/multi-threading-and-multi- Process-in-node-js-fda5bb5cde98 

Giải thích "Nút nhanh hơn vì nó không chặn ..." là một chút tiếp thị và đây là một câu hỏi hay. Đó là hiệu quả và khả năng mở rộng, nhưng không chính xác đơn luồng.


0

Sự cải thiện như xa như tôi biết là không đồng bộ I / O sử dụng (Tôi đang nói về MS System, chỉ cần làm rõ) cái gọi là I / O cổng hoàn thành . Bằng cách sử dụng lệnh gọi không đồng bộ, khung sẽ tự động thúc đẩy kiến ​​trúc như vậy và điều này được cho là hiệu quả hơn so với cơ chế phân luồng tiêu chuẩn. Theo kinh nghiệm cá nhân, tôi có thể nói rằng bạn sẽ cảm thấy ứng dụng của mình phản ứng mạnh mẽ hơn nếu bạn thích AsyncCalls thay vì chặn các luồng.


0

Hãy để tôi cung cấp cho bạn một ví dụ mẫu mà I / O không đồng bộ không hoạt động. Tôi đang viết một proxy tương tự như bên dưới - sử dụng boost :: asio. https://github.com/ArashPartow/proxy/blob/master/tcpproxy_server.cpp

Tuy nhiên, kịch bản của trường hợp của tôi là, tin nhắn đến (từ phía khách hàng) nhanh trong khi gửi đi (đến phía máy chủ) chậm trong một phiên, để theo kịp tốc độ đến hoặc tối đa hóa tổng thông lượng proxy, chúng tôi phải sử dụng nhiều phiên dưới một kết nối.

Do đó, khung I / O không đồng bộ này không hoạt động nữa. Chúng tôi cần một nhóm luồng để gửi đến máy chủ bằng cách chỉ định mỗi luồng một phiên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.