Sự khác biệt giữa một sợi và sợi là gì?


187

Sự khác biệt giữa một sợi và sợi là gì? Tôi đã nghe nói về các sợi từ ruby ​​và tôi đã đọc được rằng chúng có sẵn bằng các ngôn ngữ khác, ai đó có thể giải thích cho tôi bằng những thuật ngữ đơn giản về sự khác biệt giữa một sợi và sợi.

Câu trả lời:


162

Nói một cách đơn giản nhất, các luồng thường được coi là có khả năng ngăn chặn (mặc dù điều này có thể không phải lúc nào cũng đúng, tùy thuộc vào hệ điều hành) trong khi các sợi được coi là các sợi nhẹ, hợp tác. Cả hai đều là đường dẫn thực thi riêng cho ứng dụng của bạn.

Với các luồng: đường dẫn thực thi hiện tại có thể bị gián đoạn hoặc bị chặn bất cứ lúc nào (lưu ý: tuyên bố này là một khái quát và có thể không luôn luôn đúng tùy thuộc vào hệ điều hành / gói luồng / v.v.). Điều này có nghĩa là đối với các luồng, tính toàn vẹn dữ liệu là một vấn đề lớn vì một luồng có thể bị dừng ở giữa quá trình cập nhật một đoạn dữ liệu, khiến tính toàn vẹn của dữ liệu ở trạng thái xấu hoặc không đầy đủ. Điều này cũng có nghĩa là hệ điều hành có thể tận dụng nhiều CPU và lõi CPU bằng cách chạy nhiều hơn một luồng cùng lúc và để cho nhà phát triển bảo vệ quyền truy cập dữ liệu.

Với các sợi: đường dẫn thực hiện hiện tại chỉ bị gián đoạn khi sợi mang lại sự thực thi (cùng lưu ý như trên). Điều này có nghĩa là các sợi luôn bắt đầu và dừng ở những nơi được xác định rõ, do đó tính toàn vẹn dữ liệu ít xảy ra hơn. Ngoài ra, do các sợi thường được quản lý trong không gian người dùng, các chuyển đổi ngữ cảnh đắt tiền và thay đổi trạng thái CPU không cần phải thực hiện, việc thay đổi từ sợi này sang sợi tiếp theo cực kỳ hiệu quả. Mặt khác, vì không có hai sợi nào có thể chạy cùng một lúc, nên chỉ sử dụng các sợi sẽ không tận dụng được nhiều CPU hoặc nhiều lõi CPU.


7
Có cách nào để sử dụng nhiều luồng để thực hiện các sợi song song không?
Baradé

2
@Jason, Khi bạn tuyên bố ~ "với các sợi, đường dẫn thực hiện hiện tại chỉ bị gián đoạn khi sợi mang lại sự thực thi" và "các sợi luôn bắt đầu và dừng ở những nơi được xác định rõ để vấn đề toàn vẹn dữ liệu ít xảy ra hơn", ý bạn là Khi chia sẻ biến, chúng ta không cần sử dụng "cơ chế khóa" và biến dễ bay hơi? Hay bạn có nghĩa là chúng ta vẫn cần phải làm những điều đó?
Pacerier

@ Baradé Đó là một câu hỏi thú vị, bạn đã tìm thấy câu trả lời chưa?
Mayur

57

Chủ đề sử dụng pre-emptive lịch trình, trong khi sợi sử dụng hợp tác lập kế hoạch.

Với một luồng, luồng điều khiển có thể bị gián đoạn bất cứ lúc nào và luồng khác có thể chiếm quyền điều khiển. Với nhiều bộ xử lý, bạn có thể có nhiều luồng tất cả chạy cùng một lúc ( đa luồng đồng thời hoặc SMT). Do đó, bạn phải rất cẩn thận trong việc truy cập dữ liệu đồng thời và bảo vệ dữ liệu của bạn bằng các biến thể, ngữ nghĩa, biến điều kiện, v.v. Nó thường rất khó để có được đúng.

Với một sợi, điều khiển chỉ chuyển đổi khi bạn nói với nó, thông thường với một lệnh gọi hàm có tên như thế yield(). Điều này làm cho việc truy cập dữ liệu đồng thời dễ dàng hơn, vì bạn không phải lo lắng về tính nguyên tử của cấu trúc dữ liệu hoặc các đột biến. Miễn là bạn không chịu thua, sẽ không có nguy cơ bị cấm và có một sợi khác đang cố đọc hoặc sửa đổi dữ liệu bạn đang làm việc. Tuy nhiên, kết quả là, nếu sợi của bạn đi vào một vòng lặp vô hạn, thì không có sợi nào khác có thể chạy được, vì bạn không cho năng suất.

Bạn cũng có thể trộn các sợi và sợi, điều này dẫn đến các vấn đề mà cả hai phải đối mặt. Không được đề xuất, nhưng đôi khi nó có thể là điều đúng đắn nếu được thực hiện cẩn thận.


3
Tôi nghĩ rằng một vòng lặp vô hạn chỉ là một lỗi cần phải sửa và các luồng chỉ có một lợi thế khá mơ hồ khi có một vòng lặp vô hạn. Khái niệm không có lỗi liên quan là khi có một quá trình dài mà người dùng có thể muốn hủy bỏ. Trong trường hợp này, cho dù bạn sử dụng luồng hay sợi, quy trình chạy dài cần phải hợp tác - chỉ cần giết luồng của nó có thể khiến một số cấu trúc dữ liệu của bạn bị rối, do đó, một cách tốt hơn là ví dụ luồng xử lý dài sẽ kiểm tra định kỳ nếu nó đã bị gián đoạn. Điều này không quá khác biệt so với sợi có năng suất định kỳ.
Evgeni Sergeev

43

Trong Win32, một sợi là một loại luồng do người dùng quản lý. Một sợi có ngăn xếp riêng và con trỏ lệnh riêng của nó, v.v., nhưng các sợi không được HĐH lên lịch: bạn phải gọi SwitchToFiber một cách rõ ràng. Ngược lại, các luồng được lên lịch trước bởi hệ thống vận hành. Vì vậy, đại khái là một sợi là một luồng được quản lý ở cấp ứng dụng / thời gian chạy chứ không phải là một luồng hệ điều hành thực sự.

Hậu quả là các sợi rẻ hơn và ứng dụng có nhiều quyền kiểm soát hơn trong việc lên lịch. Điều này có thể quan trọng nếu ứng dụng tạo ra nhiều tác vụ đồng thời và / hoặc muốn tối ưu hóa chặt chẽ khi chúng chạy. Ví dụ: máy chủ cơ sở dữ liệu có thể chọn sử dụng các sợi thay vì các luồng.

(Có thể có các cách sử dụng khác cho cùng một thuật ngữ; như đã lưu ý, đây là định nghĩa Win32.)


37

Đầu tiên tôi khuyên bạn nên đọc phần giải thích này về sự khác biệt giữa các quy trình và chủ đề làm tài liệu nền.

Một khi bạn đã đọc rằng nó khá dễ dàng. Các luồng chủ đề được thực hiện hoặc trong kernel, trong không gian người dùng hoặc cả hai có thể được trộn lẫn. Sợi về cơ bản là các luồng được thực hiện trong không gian người dùng.

  • Cái thường được gọi là một luồng là một luồng thực thi được thực hiện trong kernel: cái được gọi là luồng kernel. Việc lập lịch trình của một luồng nhân được xử lý riêng bởi kernel, mặc dù một luồng nhân có thể tự nguyện giải phóng CPU bằng cách ngủ nếu muốn. Một luồng nhân có ưu điểm là nó có thể sử dụng chặn I / O và để kernel lo lắng về việc lập lịch trình. Nhược điểm chính của nó là chuyển đổi luồng tương đối chậm vì nó yêu cầu bẫy vào kernel.
  • Các sợi là các luồng không gian người dùng có lịch trình được xử lý trong không gian người dùng bởi một hoặc nhiều luồng nhân trong một quy trình. Điều này làm cho chuyển đổi sợi rất nhanh. Nếu bạn nhóm tất cả các sợi truy cập vào một tập hợp dữ liệu được chia sẻ cụ thể theo ngữ cảnh của một luồng nhân và xử lý lịch biểu của chúng bằng một luồng nhân duy nhất, thì bạn có thể loại bỏ các sự cố đồng bộ hóa do các sợi sẽ chạy nối tiếp và bạn đã hoàn thành kiểm soát lịch trình của họ. Việc nhóm các sợi liên quan dưới một luồng nhân duy nhất rất quan trọng, vì luồng nhân mà chúng đang chạy có thể được nhân trước. Điểm này không được làm rõ trong nhiều câu trả lời khác. Ngoài ra, nếu bạn sử dụng chặn I / O trong một sợi, toàn bộ luồng nhân thì nó là một phần của các khối bao gồm tất cả các sợi là một phần của luồng nhân đó.

Trong phần 11.4 "Quy trình và chủ đề trong Windows Vista" trong Hệ điều hành hiện đại, Tanenbaum nhận xét:

Mặc dù các sợi được lên lịch hợp tác, nhưng nếu có nhiều luồng lập lịch cho các sợi, rất nhiều sự đồng bộ cẩn thận được yêu cầu để đảm bảo các sợi không can thiệp lẫn nhau. Để đơn giản hóa sự tương tác giữa các luồng và các sợi, thường chỉ hữu ích khi tạo ra nhiều luồng như có các bộ xử lý để chạy chúng và xác nhận các luồng cho mỗi luồng chỉ chạy trên một bộ xử lý có sẵn riêng biệt, hoặc thậm chí chỉ một bộ xử lý. Mỗi luồng sau đó có thể chạy một tập hợp con cụ thể của các sợi, thiết lập mối quan hệ một-nhiều giữa các luồng và các sợi giúp đơn giản hóa việc đồng bộ hóa. Mặc dù vậy vẫn còn nhiều khó khăn với sợi. Hầu hết các thư viện Win32 hoàn toàn không biết về các sợi và các ứng dụng cố gắng sử dụng các sợi như thể chúng là các luồng sẽ gặp phải các lỗi khác nhau. Hạt nhân không có kiến ​​thức về các sợi và khi một sợi đi vào hạt nhân, luồng mà nó đang thực thi có thể chặn và hạt nhân sẽ lên lịch một luồng tùy ý trên bộ xử lý, khiến nó không có khả năng chạy các sợi khác. Vì những lý do này, các sợi hiếm khi được sử dụng trừ khi chuyển mã từ các hệ thống khác rõ ràng cần chức năng được cung cấp bởi các sợi.


4
Đây là câu trả lời đầy đủ nhất.
Bernard

12

Lưu ý rằng ngoài Chủ đề và Sợi, Windows 7 giới thiệu Lập lịch chế độ người dùng :

Lập lịch chế độ người dùng (UMS) là một cơ chế trọng lượng nhẹ mà các ứng dụng có thể sử dụng để lên lịch cho các luồng của riêng họ. Một ứng dụng có thể chuyển đổi giữa các luồng UMS trong chế độ người dùng mà không cần liên quan đến bộ lập lịch hệ thống và lấy lại quyền kiểm soát bộ xử lý nếu một luồng UMS chặn trong kernel. Các luồng UMS khác với các sợi trong đó mỗi luồng UMS có bối cảnh luồng riêng thay vì chia sẻ bối cảnh luồng của một luồng. Khả năng chuyển đổi giữa các luồng trong chế độ người dùng giúp UMS hiệu quả hơn nhóm luồng để quản lý số lượng lớn các mục công việc trong thời gian ngắn yêu cầu ít cuộc gọi hệ thống.

Thông tin thêm về chủ đề, sợi và UMS có sẵn bằng cách xem Dave Probert: Inside Windows 7 - Bộ lập lịch chế độ người dùng (UMS) .


7

Chủ đề được lên lịch bởi hệ điều hành (pre-emptive). Một luồng có thể bị dừng hoặc nối lại bất cứ lúc nào bởi HĐH, nhưng các sợi ít nhiều tự quản lý (hợp tác) và nhường cho nhau. Đó là, lập trình viên điều khiển khi các sợi thực hiện quá trình xử lý của chúng và khi quá trình xử lý đó chuyển sang một sợi khác.


7

Các luồng thường dựa vào nhân để làm gián đoạn luồng để nó hoặc luồng khác có thể chạy (được biết đến nhiều hơn là đa nhiệm Pre-emptive) trong khi các sợi sử dụng đa nhiệm hợp tác trong đó chính sợi đó từ bỏ thời gian chạy của nó. các sợi khác có thể chạy.

Một số liên kết hữu ích giải thích nó tốt hơn tôi có thể là:


7

Chủ đề ban đầu được tạo ra như các quá trình nhẹ. Theo cách tương tự, các sợi là một sợi nhẹ, dựa (đơn giản) vào chính các sợi để lên lịch cho nhau, bằng cách mang lại sự kiểm soát.

Tôi đoán bước tiếp theo sẽ là chuỗi mà bạn phải gửi tín hiệu cho họ mỗi khi bạn muốn họ thực hiện một lệnh (không giống như con trai 5yo của tôi :-). Ngày xưa (và thậm chí bây giờ trên một số nền tảng nhúng), tất cả các luồng đều là các sợi, không có chế độ trước và bạn phải viết các luồng của mình để hành xử độc đáo.


3

Định nghĩa sợi Win32 trên thực tế là định nghĩa "Chủ đề xanh" được thiết lập tại Sun microsystems. Không cần phải lãng phí sợi thuật ngữ trên luồng của một số loại, tức là, một luồng thực thi trong không gian người dùng dưới sự kiểm soát của mã người dùng / thư viện luồng.

Để làm rõ lập luận, hãy nhìn vào các ý kiến ​​sau:

  • Với siêu phân luồng, CPU đa lõi có thể chấp nhận nhiều luồng và phân phối chúng một trên mỗi lõi.
  • CPU đường ống siêu tốc chấp nhận một luồng để thực thi và sử dụng Parallelism Parallelism (ILP) để chạy luồng nhanh hơn. Chúng tôi có thể giả định rằng một sợi được chia thành các sợi song song chạy trong các đường ống song song.
  • CPU SMT có thể chấp nhận nhiều luồng và hãm chúng thành các sợi chỉ dẫn để thực hiện song song trên nhiều đường ống, sử dụng đường ống hiệu quả hơn.

Chúng ta nên giả định rằng các quy trình được tạo thành từ các luồng và các luồng nên được làm từ các sợi. Với logic đó, sử dụng sợi cho các loại chủ đề khác là sai.


Hay đấy.
JSON
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.