Tại sao chúng ta phải chờ I / O?


28

Người ta luôn biết rằng hoạt động của đĩa chậm và chúng tôi biết lý do tại sao chúng chậm. Vì vậy, câu hỏi ở đây là tại sao chúng ta phải chờ I / O hoặc tại sao lại có một thứ như IOWait, v.v.?

Ý tôi là tôi đã nhận thấy rằng khi bạn thực hiện một số tác vụ I / O ở chế độ nền, máy tính của bạn về cơ bản sẽ chậm hơn rất nhiều, tôi đặc biệt nhận thấy rằng khi sử dụng Linux, nếu bạn thực hiện một số tác vụ I / O dài hơn , HĐH trở nên gần như không sử dụng được cho đến khi chúng được hoàn thành.

Thật vậy, tôi cũng tìm thấy chủ đề này trong một bài báo, có một đoạn:

I / O chờ đợi là 12,1%. Máy chủ này có 8 lõi (thông qua cat / Proc / cpuinfo). Điều này rất gần với (1/8 lõi = 0,125)

Về cơ bản, điều đó có nghĩa là nó làm chậm máy tính RẤT NHIỀU, tại sao vậy? Ý tôi là OK, bây giờ máy tính bình thường có ít nhất 2 lõi, đôi khi 4 hoặc đôi khi chúng có nhiều hơn vì siêu phân luồng hoặc đại loại như thế. Nhưng bây giờ câu hỏi là tại sao CPU thực sự phải ở đó, thực tế không làm gì khác hơn là chỉ chờ IO? Ý tôi là ý tưởng cơ bản hoặc kiến ​​trúc của quy trình quản lý quy trình, bây giờ tôi không biết liệu HĐH có chịu trách nhiệm cho việc đó hay không, hay nó thuộc về phần cứng, nhưng cpu có thể chờ đợi hay không kiểm tra thường xuyên, trong khi thực sự thực hiện nhiều nhiệm vụ khác và chỉ quay lại quy trình IO khi nó sẵn sàng. Thật vậy, nếu đó là một nhiệm vụ khó khăn và cpu sẽ phải chờ, tại sao không phải là ' t mà quản lý bằng phần cứng hiệu quả hơn thì sao? Ví dụ như có thể có một loại cpu mini nào đó sẽ đợi nó và cung cấp một phần nhỏ dữ liệu cho cpu thực ngay khi nó quay trở lại quy trình và vì vậy quy trình sẽ được lặp lại và chúng ta sẽ không có để thực sự dành toàn bộ lõi cpu cho quá trình sao chép dữ liệu ... Hay tôi sẽ là người nên phát minh ra loại công cụ này và nhận được giải thưởng cao quý cho điều đó? :S

Bây giờ ổn rồi, tôi thực sự đặt nó bây giờ từ góc độ quan sát viên và tôi thực sự chưa đi sâu vào chủ đề này, nhưng tôi thực sự không hiểu tại sao cpu phải làm việc với tốc độ của ổ cứng, trong khi nó chỉ có thể làm một cái gì đó khác và quay lại với ổ cứng khi nó sẵn sàng. Ý tưởng là không tăng tốc ứng dụng cần hoạt động IO hoặc quá trình sao chép hoặc bất cứ điều gì, nhưng ý tưởng là chỉ ảnh hưởng tối thiểu đến mức tiêu thụ CPU trong khi thực hiện thao tác đó, để HĐH có thể sử dụng nó cho các quy trình khác và người dùng sẽ không phải cảm thấy độ trễ của máy tính nói chung khi thực hiện một số thao tác sao chép ...


41
"Trong khi nó chỉ có thể làm một cái gì đó khác" - chẳng hạn như? Nó cần phải làm việc với dữ liệu. Nếu dữ liệu đó không có trong bộ đệm CPU L1, nó cần tìm nạp nó từ bộ đệm L2. Nếu không có trong bộ đệm L2, nó cần tìm nạp từ L3 (nếu có). Nếu nó hoàn toàn không phải trên bộ đệm chết, nó cần truy cập vào bộ nhớ chính. Nếu không có trong bộ nhớ chính ... thì cần phải truy cập vào ổ cứng.
Oded

39
Các máy tính không làm cái gì khác; kernel chặn luồng cho đến khi hoàn thành thao tác IO, cho phép các luồng / tiến trình khác chạy. Nhưng nếu mọi thứ đang chờ trên đĩa IO, thì không có gì khác để làm.
Đại tá Ba mươi Hai

6
Bạn phải đợi các chương trình đến tháp I / O và gửi cho bạn frisbees của họ!
Almo

1
@immibis Đúng! :)
Almo

2
Thông thường các hệ điều hành hiện đại làm những gì bạn phàn nàn rằng chúng không làm - Các hoạt động IO được gửi đến phần cứng thích hợp và các ngắt được tạo bởi phần cứng để biểu thị rằng các hoạt động đã được thực hiện. Các quy trình chờ trên IO thường bị chặn trong khi chờ (điều này có thể thay đổi). Nếu nhiều quy trình đang chờ trên IO và không có quy trình nào khác có CPU để làm thì sẽ không có nhiều việc phải làm. Bạn cũng có thể kết thúc trong địa ngục mem-exchange. Viết chương trình để sử dụng hiệu quả CPU, bộ nhớ và IO đòi hỏi các kỹ năng đặc biệt và những gì khác đang chạy cũng ảnh hưởng đến những gì hoạt động tốt nhất.
chiến lược

Câu trả lời:


19

Các lược đồ I / O mà bạn đang mô tả đang được sử dụng trong máy tính.

Tại sao CPU thực sự phải ở đó, thực tế không làm gì khác hơn là chỉ chờ IO?

Đây là phương pháp I / O đơn giản nhất có thể: I / O được lập trình . Nhiều hệ thống nhúng và bộ vi xử lý cấp thấp / cấp thấp chỉ có một lệnh đầu vào và một lệnh đầu ra duy nhất. Bộ xử lý phải thực hiện một chuỗi các hướng dẫn rõ ràng cho mỗi ký tự được đọc hoặc viết.

nhưng cpu nên chờ đợi hoặc kiểm tra thường xuyên, trong khi thực sự thực hiện nhiều nhiệm vụ khác và chỉ quay lại quy trình IO khi nó sẵn sàng

Nhiều máy tính cá nhân có các chương trình I / O khác. Thay vì chờ đợi trong một vòng lặp chặt chẽ để thiết bị sẵn sàng ( chờ bận ), CPU khởi động thiết bị I / O yêu cầu thiết bị tạo ra một ngắt khi hoàn thành ( I / O điều khiển ngắt ).

Mặc dù I / O điều khiển ngắt là một bước tiến (so với I / O được lập trình), nó đòi hỏi một ngắt cho mọi ký tự được truyền và nó rất tốn kém ...

Ví dụ như có thể có một loại cpu mini nào đó sẽ đợi nó và cung cấp một phần nhỏ dữ liệu cho cpu thực ngay khi nó quay lại quy trình và vì vậy quy trình sẽ được lặp lại và chúng ta sẽ không có để thực tế dành toàn bộ lõi cpu cho quá trình sao chép dữ liệu ...

Giải pháp cho nhiều vấn đề nằm ở việc có người khác làm việc! :-)

Bộ điều khiển / chip DMA (Truy cập bộ nhớ trực tiếp) cho phép I / O được lập trình nhưng có người khác làm điều đó!

Với DMA, CPU chỉ phải khởi tạo một vài thanh ghi và bạn có thể tự do làm một việc khác cho đến khi quá trình truyền kết thúc (và một ngắt được đưa ra).

Ngay cả DMA cũng không hoàn toàn miễn phí: các thiết bị tốc độ cao có thể sử dụng nhiều chu kỳ bus để tham chiếu bộ nhớ và tham chiếu thiết bị ( đánh cắp chu kỳ ) và CPU phải chờ (chip DMA luôn có mức ưu tiên bus cao hơn).

I / O chờ đợi là 12,1%. Máy chủ này có 8 lõi (thông qua cat / Proc / cpuinfo). Điều này rất gần với (1/8 lõi = 0,125)

Tôi nghĩ đây là từ: Hiểu về I / O của đĩa - khi nào bạn nên lo lắng?

Chà không có gì lạ: hệ thống (myQuery) phải tìm nạp tất cả các hàng trước khi thao tác dữ liệu và không có hoạt động nào khác.

Ở đây không có vấn đề về kiến ​​trúc / hệ điều hành máy tính. Đó chỉ là cách ví dụ được đặt ra.

Nhiều nhất nó có thể là một vấn đề điều chỉnh RDBMS hoặc một vấn đề truy vấn SQL (thiếu chỉ mục, kế hoạch truy vấn xấu, truy vấn xấu ...)


24

Có thể ghi IO không đồng bộ trong đó bạn yêu cầu HĐH gửi một đĩa đọc / ghi và sau đó đi làm một cái gì đó khác và sau đó kiểm tra xem nó đã xong chưa. Nó mới xa. Một phương thức cũ hơn đang sử dụng một luồng khác cho IO.

Tuy nhiên, điều đó đòi hỏi bạn phải làm gì đó trong khi việc đọc đó đang được thực thi và bạn sẽ không được phép chạm vào bộ đệm mà bạn đã truyền cho kết quả.

Việc lập trình cũng dễ dàng hơn nhiều khi bạn cho rằng mọi thứ đang chặn IO.

Khi bạn gọi một chức năng đọc chặn, bạn biết rằng nó sẽ không trở lại cho đến khi một cái gì đó đã được đọc và ngay lập tức sau khi bạn có thể bắt đầu xử lý nó.

Vòng lặp đọc điển hình là một ví dụ tốt

//variables that the loop uses
char[1024] buffer;
while((read = fread(buffer, 1024, 1, file))>0){
    //use buffer
}

Mặt khác, bạn cần lưu trạng thái chức năng hiện tại (thường ở dạng con trỏ gọi lại + userData) và chuyển nó + định danh của thao tác đọc trở lại select()vòng lặp loại. Ở đó, nếu một hoạt động kết thúc, nó sẽ ánh xạ định danh của hoạt động đọc tới con trỏ dữ liệu + gọi lại và gọi lại với thông tin của hoạt động đã hoàn thành.

void callback(void* buffer, int result, int fd, void* userData){
    if(result<=0){
    //done, free buffer and continue to normal processing
    }
    //use buffer

    int readID = async_read(fd, buffer, userData->buff_size);
    registerCallback(readId, callback, userData);
}

Điều này cũng có nghĩa là mọi chức năng có thể kết thúc bằng cách đọc async đó sẽ cần có khả năng xử lý việc tiếp tục không đồng bộ. Đó là một thay đổi không hề nhỏ trong hầu hết các chương trình, bạn yêu cầu mọi người cố gắng vào async C # về điều đó.


Tuy nhiên IO đồng bộ so với IO không đồng bộ không phải là nguyên nhân gây ra sự chậm lại chung. Trao đổi trang trong cũng là một hoạt động cần phải chờ trên IO. Bộ lập lịch sẽ chỉ chuyển sang một chương trình khác không chờ trên IO nếu có ( IO chờ là khi bộ xử lý không hoạt động và có một hoạt động IO đang chờ xử lý ).

Vấn đề thực sự là cả ổ cứng và CPU đều sử dụng cùng một kênh để giao tiếp với RAM ; xe buýt bộ nhớ. Và trừ khi bạn đang sử dụng RAID thì chỉ có một đĩa duy nhất để lấy dữ liệu. Điều này trở nên tồi tệ hơn nếu bạn cũng đang sử dụng một ứng dụng chuyên sâu về đồ họa, sau đó giao tiếp với GPU cũng sẽ gây trở ngại.

Nói cách khác, nút cổ chai thực sự có lẽ nằm ở phần cứng chứ không phải phần mềm.


6
"Tuy nhiên IO đồng bộ so với IO không đồng bộ không phải là nguyên nhân gây ra sự chậm lại chung." Vậy tại sao bạn quyết định tập trung vào chủ đề tương đối nâng cao này khi câu hỏi là về những điều cơ bản?
Svick

1
Có lẽ bạn nên đề cập vài điều về DMA
Alec Teal

2
Thực tế thú vị: thực sự có một cơ chế thực sự cũ cho phép các chương trình làm việc khác trong khi thực hiện I / O mà không phải xử lý các cuộc gọi lại; nó được gọi là chủ đề .
dùng253751

2
Thảo luận tốt về ưu / nhược điểm của đồng bộ hóa / async IO. Nhưng bạn có chắc đó là lý do cho sự chậm lại? Nói chung, tôi thấy rằng sự chậm chạp trong tải IO nặng trước hết là do phần mềm được cấu trúc kém hoặc khi đó không phải là do hệ thống đang sử dụng một đĩa đơn, chậm (không phải SSD) và mọi thứ đang cố gắng truy cập đồng thời . Tôi đổ lỗi cho nút cổ chai về khả năng phục vụ các yêu cầu của đĩa trước khi tôi đổ lỗi cho sự bão hòa của bus bộ nhớ. Bạn cần lưu trữ thực sự cao cấp để bão hòa một chiếc xe buýt bộ nhớ hiện đại.
aroth

9

Có niềm tin rằng việc xử lý các công cụ khác trong khi chờ I / O khá hợp lý, gần với sự sắp xếp hợp lý nhất có thể. Khi bạn thấy rằng máy tính của bạn đang chờ I / O chỉ 12,1% thời gian, điều đó có nghĩa là trên thực tế nó đang thực hiện rất nhiều việc khác song song. Nếu nó thực sự phải đợi I / O mà không làm gì khác, thì nó sẽ đợi 99,9% thời gian, đó là tốc độ I / O chậm.

Cách duy nhất để thực hiện nhiều việc song song là dự đoán những gì người dùng có thể muốn làm tiếp theo và chúng tôi chưa thực sự giỏi trong loại dự đoán đó. Vì vậy, nếu người dùng thực hiện một thao tác yêu cầu một khu vực cụ thể được đọc từ ổ đĩa cứng và khu vực đó chưa xảy ra trong bộ đệm, thì HĐH sẽ bắt đầu quá trình đọc khu vực đó rất lâu và nó sẽ cố gắng để xem nếu có bất cứ điều gì khác để làm trong thời gian trung bình. Nếu có một người dùng khác muốn một lĩnh vực khác, nó cũng sẽ xếp hàng yêu cầu đó. Tại một số điểm, tất cả các yêu cầu đã được xếp hàng, và chúng tôi không thể làm gì ngoài việc chờ đợi một trong số chúng được thỏa mãn trước khi chúng tôi có thể tiến hành. Nó chỉ là một thực tế của cuộc sống.

CHỈNH SỬA:

Tìm một giải pháp cho vấn đề làm thế nào để làm những thứ khác trong khi thực hiện I / O sẽ là một kỳ công đáng ngưỡng mộ, bởi vì nó đồng thời là một giải pháp cho vấn đề làm thế nào để làm những thứ khác khi không hoạt động. Một kỳ công tuyệt vời đó sẽ là bởi vì điều đó có nghĩa là bạn sẽ tìm được công việc cho máy tính của mình để làm, trong khi nó không có gì cả.

Bạn thấy đấy, đây là những gì đang xảy ra: máy tính của bạn chỉ ngồi 99,99%, không làm gì cả. Khi bạn cho nó một cái gì đó để làm, nó đi và làm nó. Nếu làm như vậy nó phải đợi I / O, nó ngồi đó và chờ đợi. Nếu nó có việc khác để làm trong khi thực hiện I / O, thì nó cũng làm điều đó. Nhưng nếu nó không có gì khác để làm ngoài I / O, thì nó phải ngồi ở đó và đợi I / O hoàn thành. Không có cách nào để khắc phục điều đó, ngoài việc đăng ký vào SETI @ Home.


Vâng, ví dụ 12,1% là từ một trang web và ví dụ được lấy từ một máy chủ có 8 lõi, ý tưởng cho rằng gần như toàn bộ một lõi chỉ được dành riêng cho các hoạt động đó, chắc chắn các lõi khác được tự do làm bất cứ điều gì và với 8 lõi bạn khá giả, nhưng nếu bạn chỉ có một lõi thì sao? : /
Arturas M

3
@ArturasM Hoặc bạn đã hiểu sai những gì trang web đang nói hoặc tác giả của trang web đã hiểu sai điều gì đó. Một máy tính chỉ có một lõi sẽ mất ít thời gian chờ đợi I / O hơn (vì tất cả các tác vụ không chờ IO, đang thực thi trên các lõi khác trong khi một lõi không hoạt động, tất cả sẽ phải thực thi trên một lõi cốt lõi). I / O mất một khoảng thời gian nhất định để xảy ra cho dù bạn có chờ đợi hay không - có thời gian để chờ đợi nó là một triệu chứng không có gì khác để làm với thời gian đó.
Random832

6

HĐH (trừ khi nó là một hệ thống nhúng ở mức rất thấp hoặc một thứ gì đó tương tự kỳ lạ) đã xử lý vấn đề này: nếu ứng dụng của bạn phải chờ I / O, nó thường sẽ chặn I / O đó và một số luồng hoặc ứng dụng khác sẽ trở thành chủ động. Người lập lịch quyết định cái nào.

Chỉ khi không có luồng hoặc ứng dụng nào khác có thể chạy mà bạn thực sự tích lũy thời gian chờ. Trong bài viết bạn đã trích dẫn (nhờ @manlio cho liên kết), đó là trường hợp: bạn có 12,1% chờ so với 87,4% không hoạt động, có nghĩa là một lõi đang chờ I / O hoàn thành trong khi phần còn lại không làm gì cả ở tất cả. Cung cấp cho hệ thống đó một cái gì đó để làm, tốt nhất là nhiều lần, và tỷ lệ phần trăm chờ sẽ giảm.

Một trong những mục tiêu cao của thiết kế ứng dụng ngày nay là đảm bảo rằng ngay cả khi chỉ có một ứng dụng duy nhất đang chạy và ngay cả khi ứng dụng đó đang chờ I / O, ứng dụng vẫn có thể tiếp tục một số công việc khác. Chủ đề là một cách tiếp cận, không chặn I / O khác, nhưng nó phụ thuộc rất nhiều vào loại công việc bạn đang làm, cho dù bạn thực sự có thể hoàn thành công việc mà không cần dữ liệu bạn chờ đợi.

khi sử dụng Linux, nếu bạn đang thực hiện một số tác vụ I / O dài hơn, HĐH sẽ gần như không sử dụng được cho đến khi hoàn thành.

Đó thường là một dấu hiệu của một số tình huống ràng buộc I / O. Tôi dám nói rằng hệ thống không bị chậm vì nó không thể xử lý đủ CPU. Nhiều khả năng nó chậm vì một số thứ phụ thuộc vào dữ liệu từ ổ cứng, lúc đó đang bận. Đây có thể là các ứng dụng bạn muốn chạy nhưng phải tải các tệp thực thi, tệp thư viện, biểu tượng, phông chữ và các tài nguyên khác. Nó có thể là các ứng dụng bạn đã chạy, nhưng đã tráo đổi một phần bộ nhớ của chúng và bây giờ cần phải đổi chỗ đó một lần nữa để tiếp tục. Nó có thể là một số daemon mà vì lý do này hay lý do khác nghĩ rằng nó không chỉ phải viết một dòng vào một tệp nhật ký mà còn thực sự xóa tệp nhật ký đó trước khi trả lời một số yêu cầu.

Bạn có thể sử dụng các công cụ như iotopđể xem cách phân bổ dung lượng I / O cho các quy trình và ioniceđể đặt mức độ ưu tiên I / O cho các quy trình. Ví dụ: trên máy tính để bàn, bạn có thể phân loại tất cả xử lý dữ liệu hàng loạt cho idlelớp lập lịch, để thời điểm một số ứng dụng tương tác cần băng thông I / O, việc xử lý hàng loạt sẽ bị đình chỉ cho đến khi ứng dụng tương tác hoàn tất.


5

Nó phụ thuộc vào mã ứng dụng của bạn. Tôi cho rằng mã của bạn đang chạy trên Linux.

Bạn có thể sử dụng đa luồng (ví dụ pthreads POSIX ) để có các luồng liên kết tính toán thực hiện một số tính toán trong khi các luồng liên kết IO khác đang thực hiện IO (và chờ đợi nó). Bạn thậm chí có thể có ứng dụng của mình chạy một số quy trình giao tiếp với giao tiếp giữa các quá trình (IPC), xem ống dẫn (7) , fifo (7) , ổ cắm (7) , unix (7) , shm_overview (7) , sem_overview (7) , mmap (2) , eventfd (2) và đọc Lập trình Linux nâng cao, v.v ....

Bạn có thể sử dụng IO không chặn , ví dụ: pass O_NOBLOCKđể mở (2), v.v., v.v ...; sau đó bạn sẽ cần bỏ phiếu (2) và / hoặc sử dụng SIGIO tín hiệu (7) ... và xử lý EWOULDBLOCKlỗi từ đọc (2), v.v ...

Bạn có thể sử dụng IO không đồng bộ POSIX, xem aio (7)

Để truy cập tệp, bạn có thể đưa ra gợi ý cho bộ đệm trang , ví dụ như với madvise (2) sau mmap (2) và với posix_fadvise (2) ; xem thêm phần đọc cụ thể của Linux (2)

Nhưng cuối cùng bạn sẽ gặp phải một số tắc nghẽn phần cứng (xe buýt, RAM, v.v.). Xem thêm ionice (1)


1

Tôi thêm quan điểm khác hơn những người khác, có thể gây tranh cãi:

Vấn đề điển hình của hệ điều hành Linux. Độ trễ cụ thể (Tìm kiếm "độ trễ chuột Linux"). Windows không có vấn đề này. Tôi có Windows 7 và Linux Mint khởi động kép. Ngay cả khi thực hiện thao tác đĩa chuyên sâu trong Windows, Windows vẫn cảm thấy mượt mà, chuột vẫn di chuyển bình thường. Trong Linux đối nghịch, nó không có cảm giác như vậy và đôi khi chuột bị lag ngay cả khi duyệt web bình thường.

Có lẽ bởi vì triết lý và lịch sử khác nhau của hai hệ thống này. Windows ngay từ đầu được thiết kế cho người dùng thông thường, các hệ thống hoạt động đồ họa chủ yếu của nó. Và đối với người dùng Windows, hành vi hệ thống không mượt mà và chuột ngừng di chuyển là tín hiệu cho thấy có gì đó không ổn. Vì vậy, các lập trình viên của microsofts đã làm việc chăm chỉ để thiết kế toàn bộ hệ thống để giảm thiểu các trường hợp khi hệ thống cảm thấy chậm. Ngược lại, Linux không phải là hệ thống đồ họa ban đầu, máy tính để bàn chỉ là sự bổ sung của bên thứ 3 tại đây. Và Linux được thiết kế chủ yếu cho các tin tặc sử dụng dòng lệnh. Làm mọi việc theo triết lý. Linux đơn giản là không được thiết kế cho hành vi trơn tru trong tâm trí, cảm xúc không quan trọng ở đây.

Lưu ý: Tôi không nói rằng Windows tốt hơn Linux, tôi nói đơn giản là họ có triết lý chung khác nhau, trong môi trường phức tạp có thể dẫn đến hành vi / cảm giác ở mức độ cao khác nhau của các hệ thống này.


Có thể tránh hoặc giảm độ trễ chuột Linux bằng cách cấu hình cẩn thận của hệ thống (ví dụ: sử dụng nice& ionicetrên các quy trình đói). Và tôi sử dụng Linux và hầu như chưa bao giờ gặp phải sự cố chuột Linux (trừ khi quá tải máy tính của tôi ...)
Basile Starynkevitch

BTW, Linux chủ yếu là một hệ điều hành máy chủ.
Basile Starynkevitch

Tôi sẽ lưu ý rằng tôi đã gặp phải hiện tượng giật UI và chuột trên Windows 7, ngay cả trong thời gian khi Trình quản lý tác vụ và Trình giám sát tài nguyên chỉ ra mức sử dụng bộ nhớ thấp và hoạt động của CPU và ổ đĩa thấp.
8bittree
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.