Đây có phải là một hit hiệu suất để tạo ra các chủ đề lặp rất nhiều để kiểm tra mọi thứ?


8

Đây là một câu hỏi chung chung mà tôi luôn tự hỏi.

Nói chung, CPU có chuyên sâu để tạo ra các luồng thực hiện các vòng lặp "trong khi không đúng ..." hay tương tự không?

Ví dụ: giả sử tôi làm:

// pseudo-code
new Thread(function() {
    while (!useHasDoneSomething) {
        // do nothing...
    }
    alert("you did something!");
}

Vì vậy, nó chỉ là một đoạn mã chạy trong một chuỗi chờ đợi điều gì đó xảy ra.

Vì lý do gì tôi tưởng tượng rằng điều này sẽ gây áp lực cho CPU. Rốt cuộc, mặc dù chỉ là một vòng lặp nhỏ, nhưng nó lại chạy vòng lặp ngay khi một chu trình được thực hiện. Điều này có nghĩa là nó sẽ trải qua chu kỳ nhiều lần trong một phần nghìn giây chứ? ... Mỗi nano giây!?

Hệ điều hành sẽ "xử lý" chương trình và (các) luồng, phải không? Nhưng đó vẫn là một sự chú ý khủng khiếp để chạy một vòng lặp. Nếu CPU không có gì khác để làm, nó sẽ không tập trung vào vòng lặp đó, do đó sẽ tiêu tốn hết thời gian nhàn rỗi ?

Điều gì xảy ra nếu tôi tạo 1000 chủ đề mà tất cả thực hiện cùng một vòng lặp? Làm thế nào điều đó có thể ảnh hưởng đến hiệu suất / chu kỳ CPU?

Hơn nữa, đây là cách các sự kiện hoạt động trong nội bộ? Khi bạn đang 'lắng nghe' cho một sự kiện bằng Java, .NET, Javascript, v.v. (chẳng hạn như nhấn nút hoặc thay đổi kích thước cửa sổ), có một chuỗi vòng lặp được tạo không?


1
Những gì các hồ sơ nói với bạn?
Arseni Mourzenko

2
Câu hỏi của tôi là chung chung. Không quá nhiều một câu hỏi về con số nhưng nhiều hơn "Điều gì sai với sự hiểu biết của tôi?"
Rowan Freeman

Hiểu rồi. +1 rồi.
Arseni Mourzenko

Câu trả lời:


12

Nói chung, CPU có chuyên sâu để tạo ra các luồng thực hiện các vòng lặp "trong khi không đúng ..." hay tương tự không?

Đúng. Sử dụng một vòng lặp như vậy được gọi là chờ đợi bận rộn và nó được gọi là vì lý do. Các vòng lặp bận rộn này kiểm tra tình trạng thường xuyên và nhanh như bộ xử lý có thể quản lý nó, với kết quả là, nếu bạn ở trong vòng lặp đủ lâu, tải bộ xử lý sẽ đáng tin cậy đến 100%.

Điều gì xảy ra nếu tôi tạo 1000 chủ đề mà tất cả thực hiện cùng một vòng lặp? Làm thế nào điều đó có thể ảnh hưởng đến hiệu suất / chu kỳ CPU?

Nó chỉ tạo ra nhiều công việc hơn cho CPU làm việc.

Hơn nữa, đây là cách các sự kiện hoạt động trong nội bộ? Khi bạn đang 'lắng nghe' cho một sự kiện bằng Java, .NET, Javascript, v.v. (chẳng hạn như nhấn nút hoặc thay đổi kích thước cửa sổ), có một chuỗi vòng lặp được tạo không?

Không. Các vòng lặp bận rộn là một hình thức bỏ phiếu và cũng rất kém hiệu quả. Các hệ điều hành có các cơ chế khác để phát hiện rằng một sự kiện đã xảy ra (ví dụ như một cuộc gọi bị gián đoạn hoặc một cuộc gọi cụ thể) và chúng có các cơ chế để cho một luồng chờ nó mà không tốn thời gian của CPU. Các cơ chế này cũng sẽ được sử dụng để thực hiện các cơ chế sự kiện của các ngôn ngữ như Java.


Cảm ơn! Điều gì nếu bạn ngủ các chủ đề trong thời gian ngắn, có thể 100 mili giây, trong vòng lặp? Điều đó có làm chậm luồng đủ để các chu kỳ CPU không bị lãng phí thường xuyên và do đó hiệu suất sẽ phục hồi?
Rowan Freeman

1
@RowanFreeman: Nó giảm tải cho bộ xử lý, nhưng nó vẫn sẽ cao hơn chỉ đơn giản là chờ HĐH cho bạn biết rằng X đã xảy ra.
Bart van Ingen Schenau

9

Bản năng của bạn là chính xác. Bận rộn chờ đợi như thế được mô tả là

Kéo sợi có thể là một chiến lược hợp lệ trong một số trường hợp nhất định, đáng chú ý nhất là trong việc thực hiện spinlocks trong các hệ điều hành được thiết kế để chạy trên các hệ thống SMP. Tuy nhiên, nói chung, kéo sợi được coi là một mô hình chống và nên tránh, vì thời gian của bộ xử lý có thể được sử dụng để thực hiện một tác vụ khác thay vào đó lại lãng phí cho hoạt động vô dụng.

Thay vào đó, bạn nên xem xét một nguyên hàm kiểm soát đồng thời cho phép luồng thực sự không hoạt động cho đến khi nó có công việc hữu ích để làm, ví dụ như một semaphore hoặc một biến điều kiện :

Đối với nhiều ứng dụng, loại trừ lẫn nhau là không đủ. Chủ đề cố gắng một hoạt động có thể cần phải đợi cho đến khi một số điều kiện đúng. Một vòng lặp chờ đợi bận rộn, như

while not( condition ) do 
   // nothing
end

sẽ không hoạt động, vì loại trừ lẫn nhau sẽ ngăn bất kỳ luồng nào khác đi vào màn hình để làm cho điều kiện đúng. Các "giải pháp" khác tồn tại. Chẳng hạn như có một vòng lặp mở khóa màn hình, chờ một số tiền nhất định, khóa màn hình và kiểm tra tình trạng P. Về mặt lý thuyết, nó hoạt động và sẽ không bế tắc, nhưng có vấn đề phát sinh. Thật khó để quyết định một lượng thời gian chờ thích hợp, quá nhỏ và luồng sẽ làm hỏng CPU, quá lớn và rõ ràng là nó sẽ không phản hồi. Điều cần thiết là một cách để báo hiệu luồng khi điều kiện P là đúng (hoặc có thể đúng). Giải pháp là các biến điều kiện. Về mặt khái niệm, một biến điều kiện là một chuỗi các luồng, được liên kết với một màn hình, trên đó một luồng có thể đợi một số điều kiện trở thành đúng. Do đó, mỗi biến điều kiện được liên kết với một khẳng định. Trong khi một luồng đang chờ trên một biến điều kiện, thì luồng đó không được coi là chiếm màn hình và vì vậy các luồng khác có thể vào màn hình để thay đổi trạng thái của màn hình. Trong hầu hết các loại màn hình, các luồng khác có thể báo hiệu biến điều kiện để chỉ ra rằng khẳng định là đúng trong trạng thái hiện tại.


Vì vậy, bận rộn chờ đợi nhiều của một hiệu suất hit? Là một vòng lặp duy nhất (mặc dù bắn liên tục) có bất kỳ rắc rối nào không?
Rowan Freeman

1
@RowanFreeman Đó là. Chờ đợi bận rộn, như văn bản gợi ý, tiếp tục ghi các chu kỳ CPU theo các hướng dẫn vô dụng ( nghĩa là lặp đi lặp lại if (!useHasDoneSomething)nhiều lần, nhanh nhất có thể). Ngay cả khi bạn không nhớ nó trong chương trình của mình, nó sẽ lãng phí thời gian mà các chương trình khác có thể sử dụng để chạy. Nhưng ngay cả trong chương trình của bạn, một người phục vụ bận rộn sẽ lãng phí thời gian có thể được chỉ định cho một số luồng công nhân (trong trường hợp không có đủ lõi để tất cả các luồng chạy đồng thời).
afsantos

2
@afsantos Có những cách sử dụng hợp lệ cho việc chờ đợi bận rộn - các lựa chọn thay thế thường ngụ ý giải thích chủ đề của bạn và sắp xếp lại sau. Nếu bạn biết bạn sẽ không lặp lại nhiều hơn một vài chu kỳ CPU, thì việc chờ đợi bận rộn sẽ hiệu quả hơn nhiều so với việc cho phép chuyển đổi ngữ cảnh.
assylias

1
@assylias Thật vậy, một chuyển đổi ngữ cảnh có thể là một cú hích hiệu suất, nếu biết rằng thời gian chờ đợi là rất ngắn. Tuy nhiên, từ kinh nghiệm của tôi, chờ đợi bận rộn là không phù hợp thường xuyên hơn không. OP sẽ phải đánh giá trường hợp cá nhân của anh ta, để xem liệu nó có đáng hay không.
afsantos

2

Chủ đề nên chờ cho các sự kiện đến, không phải cho các thay đổi biến.

Các sự kiện đến là các ngữ nghĩa trở nên khả dụng, hàng đợi tin nhắn trở nên không trống hoặc thời gian trôi qua:

semGet()
msqRead()
sleep()

Từ quan điểm luồng, các lệnh gọi hàm này đang chặn: luồng chờ cho đến khi sự kiện đến, để lại tải CPU cho các luồng khác.

Từ quan điểm hệ thống, chuỗi được đánh dấu là 'Đang chờ sự kiện' và sẽ không được lên lịch miễn là sự kiện chưa đến.

Về các sự kiện phần cứng, chúng được xử lý thông qua các ngắt là tín hiệu điện đến CPU và kích hoạt việc thực thi ISR ​​(các dịch vụ gián đoạn), có vai trò là tạo ra một sự kiện phần mềm trên semaphores, hàng đợi tin nhắn hoặc thời gian.


0

Phần //do nothing bên trong điều kiện trong kịch bản bình thường là WAIT trên một số semaphore, hoặc trong các điều khoản khác SLEEP. Ngủ cho đến khi một số gián đoạn đã đánh thức bạn dậy. Và do đó, luồng đi trong "trạng thái ngủ" hoặc cho phép chỉ nói "không chạy trạng thái". Chỉ các quá trình đang ở trạng thái chạy mới tiêu thụ CPU. Quá trình trạng thái ngủ sẽ không tiêu thụ CPU. Họ có thể đang tiêu thụ bộ nhớ, nhưng bộ nhớ đó sẽ bị hoán đổi bên trong bởi hệ thống bộ nhớ ảo. Vì vậy, ngay cả khi bạn tạo 1000 luồng như vậy, chúng sẽ không gây ra nhiều mối đe dọa cho hệ thống của bạ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.