Tôi mở Trình quản lý tác vụ và nhìn vào khu vực "Hệ thống" và thấy:
Chủ đề: 1337
Vì tôi có bộ xử lý lõi kép có siêu phân luồng khả dụng (nghĩa là bốn luồng), làm sao có thể có hơn 1000 luồng khi bộ xử lý của tôi chỉ có bốn luồng ?
Tôi mở Trình quản lý tác vụ và nhìn vào khu vực "Hệ thống" và thấy:
Chủ đề: 1337
Vì tôi có bộ xử lý lõi kép có siêu phân luồng khả dụng (nghĩa là bốn luồng), làm sao có thể có hơn 1000 luồng khi bộ xử lý của tôi chỉ có bốn luồng ?
Câu trả lời:
Câu trả lời đơn giản là không phải tất cả các luồng đều được thực thi đồng thời. Để giải thích đầy đủ hơn, hãy đọc tiếp.
Lập lịch tác vụ của hệ điều hành thường được nghĩ đến để lên lịch cho các ứng dụng và làm như vậy cho phép bạn thực hiện một tác vụ trong khi máy tính đang làm việc khác. Vào thời xưa, bài kiểm tra đa nhiệm về đa nhiệm là định dạng một đĩa mềm trong khi làm việc khác. Nếu bạn muốn thực sự đưa HĐH vào thử nghiệm, bạn sẽ định dạng đĩa mềm trong khi tải xuống tệp qua modem được kết nối với cổng nối tiếp. Khi phần cứng trở nên đủ mạnh để thực sự làm điều đó một cách có ý nghĩa, phát lại video đôi khi cũng xuất hiện trong các thử nghiệm như vậy. Nếu bộ lập lịch tác vụ của HĐH có thể xử lý các tác vụ đó một cách trơn tru, thì nó có thể xử lý mọi thứ.
Tuy nhiên, trình lập lịch tác vụ không thực sự lên lịch cho các ứng dụng (quy trình), nó lập lịch các luồng . Mỗi ứng dụng có ít nhất một luồng, nhưng có khả năng có thể sử dụng một số lượng lớn các luồng để phân chia công việc mà nó thực hiện thành các phần liên quan hoặc độc lập. Ví dụ, thông thường, một ứng dụng có một luồng xử lý giao diện người dùng và tạo một luồng khác khi người dùng bắt đầu một hoạt động có khả năng chạy dài (có thể là những việc như in, tính toán lại bảng tính, môi trường phát triển đang làm tra cứu biểu tượng, v.v.) Một số môi trường lập trình giới thiệu một số lượng chủ đề vô hình cho lập trình viên; ví dụ, Java và .NET có thể thực hiện thu gom ráctrong một luồng riêng biệt, nằm ngoài tầm kiểm soát ngay lập tức của lập trình viên. Một số chương trình tạo ra một số chủ đề sớm và tập hợp chúng, bởi vì tạo chủ đề mới là một hoạt động tương đối tốn kém (vì vậy bạn không nhất thiết phải tạo một chủ đề mỗi khi bạn cần một chủ đề). Bất cứ điều gì thực hiện xem trước thường được thực hiện trong một luồng riêng biệt, vì vậy phần còn lại của giao diện người dùng vẫn phản hồi trong khi bản xem trước đang được tạo. Và như thế. Được kết hợp với nhau, tất cả điều này có nghĩa là số lượng luồng trên hệ thống bất cứ lúc nào có thể dễ dàng gấp nhiều lần số lượng quy trình.
Mỗi luồng có thể ở một trong một vài trạng thái có thể, nhưng sự khác biệt quan trọng nhất là giữa trạng thái chạy , chạy và chờ ; thuật ngữ có thể khác nhau một chút, nhưng đó là ý tưởng chung. Tại bất kỳ thời điểm nào, chỉ có một luồng trên mỗi luồng ảo (vì siêu phân luồng và các công nghệ tương tự) lõi CPU có thể chạy (nghĩa là thực thi các hướng dẫn mã máy), nhưng bất kỳ số lượng luồng nào cũng có thể chạy được (có nghĩa là nó phải là ứng cử viên CPU trong lần tiếp theo bộ lập lịch cần đưa ra quyết định về luồng nào sẽ được phép chạy). Đang chờ đợi Các chủ đề (còn được gọi là bị chặn) chỉ là như vậy, chờ đợi một cái gì đó - trường hợp phổ biến nhất có lẽ là nó đang chờ người dùng, đĩa hoặc mạng I / O (đặc biệt là đầu vào của người dùng rất chậm).
Số lượng luồng bạn thấy trong trình quản lý tác vụ là tổng số luồng trong bất kỳ trạng thái nào. Ví dụ, hệ thống Windows 7 tôi đang gõ này hiện có khoảng 70 quy trình được bắt đầu nhưng gần 900 luồng. Với tất cả các quy trình nền để xử lý các tác vụ khác nhau và cách chúng có thể được chia thành vô số các chủ đề, đây không phải là một con số quá đáng.
Đi sâu hơn một chút vào chiều sâu của việc triển khai kỹ thuật, cốt lõi của bộ lập lịch tác vụ của hệ điều hành đa nhiệm ưu tiên thường là một loại móc nối phần cứng. Điều này có nghĩa rằng các hạt nhân có thể ngăn chặn sự CPU khi nó không có công việc hữu ích để thực hiện (điều này là gần như chắc chắn là một trong những lý do này, nếu không muốn nói là lý do, tại sao kiểm tra Linux các HLT
hướng dẫn khi khởi động trên IA-32CPU tương thích và có thể kiểm tra tương tự trên các kiến trúc khác), an toàn với kiến thức rằng tại một thời điểm nào đó xác định hợp lý thời gian trong tương lai, một ngắt sẽ kích hoạt và bộ lập lịch nhiệm vụ sẽ được gọi. Do ngắt hoạt động bất kể CPU đang thực hiện công việc nào khác (đó là ý tưởng đằng sau các ngắt), bộ lập lịch được thực thi thường xuyên và có cơ hội xác định luồng nào sẽ được thực hiện trong lát cắt thời gian sau. Vì các chuyển đổi ngữ cảnh tương đối đắt tiền, nên thường có thể (ít nhất là thông qua mã nguồn) để điều chỉnh mức độ mạnh mẽ của trình lập lịch chuyển đổi giữa các luồng; chuyển đổi chủ đề thường xuyên hơn làm cho hệ thống trở nên nhạy hơn, nhưng chi phí chuyển đổi có nghĩa là thời gian tổng thể để hoàn thành một tập hợp các nhiệm vụ nhất định là lâu hơn. các nhanh nhấthệ thống sẽ là một hệ thống chỉ chuyển đổi giữa các luồng khi luồng chạy không thể chạy được nữa (nghĩa là nó bị chặn chờ đợi trên một cái gì đó hoặc nó đã hoàn thành công việc của nó) bởi vì điều đó giảm thiểu chi phí, trong khi hệ thống nhạy nhất sẽ chuyển đổi giữa các luồng mỗi khi bộ lập lịch được gọi vì điều đó giảm thiểu thời gian trung bình để chờ trước khi một luồng cụ thể có thời gian CPU. Cài đặt lý tưởng thường nằm ở đâu đó ở giữa hai điều này và sự đánh đổi giữa các lựa chọn đó có thể là một lý do lớn khiến Linux cung cấp nhiều bộ lập lịch để lựa chọn cũng như một số tham số điều chỉnh thông qua cấu hình kernel.
Mặt khác, các hệ điều hành và môi trường đa nhiệm hợp tác ( Windows 3.x là một ví dụ), dựa vào từng ứng dụng để thường xuyên nhường quyền kiểm soát cho bộ lập lịch. Thường có một hàm API đặc biệt có nghĩa là để làm điều đó và thông thường, nhiều hàm API sẽ thực hiện nó như một phần của luồng thực thi nội bộ của chúng, bởi vì nó giúp trải nghiệm người dùng mượt mà hơn. Cách tiếp cận thiết kế đó hoạt động tốt miễn là tất cả các ứng dụng đều hoạt động tốt và kiểm soát các khoảng thời gian ngắn trong bất kỳ hoạt động dài nào (chạy dài có nghĩa là nhiều hơn một phần nhỏ của giây), nhưng một ứng dụng không thể làm tắc nghẽn toàn bộ hệ thống. Đây là một lý do lớn khiến Windows 3.x làm rất kém trong bài kiểm tra đa nhiệm mà tôi đã đề cập ở trên, trong khi OS / 2đi bộ vui vẻ trong khi thực hiện các nhiệm vụ tương tự trên cùng một phần cứng: một ứng dụng có thể yêu cầu ổ đĩa mềm ghi một khu vực nhất định và thời gian cần thực hiện trước khi cuộc gọi trở lại thực sự có thể đo lường được (hàng chục đến hàng trăm mili giây hoặc hơn); một hệ thống đa nhiệm được ưu tiên sẽ ngắt lịch trình trong lệnh gọi theo lịch trình tiếp theo của nó, lưu ý rằng luồng hiện đang "chạy" thực sự bị chặn bởi lệnh gọi và chỉ cần chuyển sang một luồng khác có thể chạy được. (Trong thực tế, nó liên quan nhiều hơn một chút, nhưng đó là ý tưởng chung.)
Trong cả hai môi trường đa nhiệm và hợp tác ưu tiên, cũng có khả năng các luồng khác nhau có các ưu tiên khác nhau. Ví dụ, điều quan trọng hơn là phải thực hiện kịp thời luồng xử lý nhận dữ liệu qua liên kết truyền thông so với luồng cập nhật hiển thị thời gian hệ thống, vì vậy luồng nhận có mức độ ưu tiên cao và luồng cập nhật hiển thị thời gian có mức độ ưu tiên thấp . Các ưu tiên của luồng đóng vai trò trong quyết định của trình lập lịch biểu cho phép thực hiện luồng nào (ví dụ: rất đơn giản, các luồng ưu tiên cao phải luôn luôn thực thi trước các luồng có mức độ ưu tiên thấp, vì vậy ngay cả khi luồng có mức độ ưu tiên thấp còn phải làm, nếu luồng có mức độ ưu tiên cao có thể chạy được thì nó vẫn được ưu tiên), nhưng các quyết định lập lịch cụ thể như vậy không ảnh hưởng đến thiết kế cơ chế bên dưới.
Hãy nghĩ về một đường cao tốc bốn làn với 1037 xe.
Hệ điều hành của bạn cần rất nhiều quy trình đang chạy để hoạt động cho nhiều dịch vụ. Ngay cả các chương trình đồ họa đơn giản nhất cũng sẽ yêu cầu lập trình đa luồng. Khi bạn nghĩ về rất nhiều chương trình đã mở, bạn thấy cần phải chia sẻ tài nguyên sức mạnh tính toán.
Những gì trình quản lý tác vụ của bạn đang hiển thị là tải hệ thống hiện tại. Thông số kỹ thuật comp của bạn đang hiển thị là có bao nhiêu luồng (ở lối vào) được chấp nhận để thực hiện song song. Không cần nhập nhiều vào sự khác biệt giữa các tính năng siêu phân luồng và đa lõi, với việc chấp nhận luồng frontend logic hơn, một hệ thống thường sẽ hoạt động tốt hơn.
DoEvents
, sẽ xử lý hàng đợi tin nhắn - nhưng điều đó được thực hiện trên cùng một luồng và sẽ chặn hoạt động chạy dài đó cho đến khi tất cả các tin nhắn được xử lý . (Tất nhiên, bạn có thể gọi các hàm API Win32 và / hoặc tạo các quy trình bổ sung, nhưng tại thời điểm đó, bạn cũng có thể sử dụng một trong các ngôn ngữ cấp thấp hơn.)
Chúng ta nên lùi lại và tự hỏi: Làm thế nào một máy tính với một CPU có hai luồng?
Chủ đề là các thực thể phần mềm, không phải phần cứng. Để có một luồng khác, bạn chỉ cần bộ nhớ cho các đối tượng tạo nên luồng, chẳng hạn như cấu trúc mô tả và ngăn xếp.
Hệ điều hành chuyển đổi giữa các luồng tại nhiều thời điểm khác nhau, như bên trong các ngắt nhất định (chẳng hạn như ngắt hẹn giờ) hoặc khi các luồng thực hiện cuộc gọi vào hệ điều hành.
Trong số tất cả các luồng tồn tại trong hệ thống, chỉ có một tập hợp con thường ở trạng thái thường được gọi là "runnable". Các chuỗi có thể chạy được háo hức để chạy: chúng đang thực thi hoặc đang ngồi trong "hàng đợi chạy", chờ đợi để được gửi bởi bộ lập lịch. Các chủ đề không thể chạy được là "bị chặn", đang chờ để lấy một số tài nguyên hoặc nhận đầu vào hoặc "ngủ" giống như bị chặn trên đầu vào, trong đó "đầu vào" là thời gian trôi qua. "Chuyển đổi ngữ cảnh" diễn ra khi chức năng lập lịch biểu trong hệ điều hành xem xét hàng đợi chạy của bộ xử lý và chọn một luồng khác để thực thi.
Đừng nhầm lẫn với "siêu phân luồng" , đó là tên của Intel cho một tính năng phần cứng cụ thể.