Các thuật ngữ của CPU CPU bị ràng buộc là gì


Câu trả lời:


452

Nó khá trực quan:

Một chương trình bị ràng buộc bởi CPU nếu nó đi nhanh hơn nếu CPU nhanh hơn, tức là nó dành phần lớn thời gian của nó chỉ đơn giản là sử dụng CPU (thực hiện các phép tính). Một chương trình tính các chữ số mới của π thường sẽ được giới hạn bởi CPU, nó chỉ là các số giòn.

Một chương trình bị ràng buộc I / O nếu nó đi nhanh hơn nếu hệ thống con I / O nhanh hơn. Hệ thống I / O chính xác nào có nghĩa là có thể thay đổi; Tôi thường liên kết nó với đĩa, nhưng tất nhiên nói chung là kết nối mạng hoặc giao tiếp là phổ biến. Một chương trình xem qua một tệp khổng lồ cho một số dữ liệu có thể bị ràng buộc I / O, vì nút cổ chai sau đó là việc đọc dữ liệu từ đĩa (thực ra, ví dụ này có lẽ là kiểu cũ ngày nay với hàng trăm MB / s đến từ SSD).


Làm thế nào điều này liên quan đến việc hiểu giao tiếp HTTP trên thiết bị di động? Tôi đã thấy việc sử dụng CPU tăng đột biến từ việc sử dụng các hoạt động java.nio .
IgorGanapolsky

I / O là "đầu vào / đầu ra".
Đồng chí Che

247

Giới hạn CPU có nghĩa là tốc độ tiến trình xử lý bị giới hạn bởi tốc độ của CPU. Một tác vụ thực hiện các phép tính trên một tập hợp số nhỏ, ví dụ nhân các ma trận nhỏ, có khả năng bị ràng buộc CPU.

Giới hạn I / O có nghĩa là tốc độ tiến trình của quá trình bị giới hạn bởi tốc độ của hệ thống con I / O. Một tác vụ xử lý dữ liệu từ đĩa, ví dụ, đếm số lượng dòng trong một tệp có khả năng bị ràng buộc I / O.

Giới hạn bộ nhớ có nghĩa là tốc độ tiến trình xử lý bị giới hạn bởi số lượng bộ nhớ khả dụng và tốc độ truy cập bộ nhớ đó. Một tác vụ xử lý một lượng lớn dữ liệu bộ nhớ, ví dụ như nhân các ma trận lớn, có khả năng là Giới hạn bộ nhớ.

Ràng buộc bộ đệm có nghĩa là tốc độ tiến trình xử lý bị giới hạn bởi số lượng và tốc độ của bộ đệm có sẵn. Một tác vụ chỉ đơn giản là xử lý nhiều dữ liệu hơn phù hợp với bộ đệm sẽ bị ràng buộc bộ đệm.

Giới hạn I / O sẽ chậm hơn Giới hạn bộ nhớ sẽ chậm hơn Giới hạn bộ đệm sẽ chậm hơn Giới hạn CPU.

Giải pháp để bị ràng buộc I / O không nhất thiết phải có thêm Bộ nhớ. Trong một số trường hợp, thuật toán truy cập có thể được thiết kế xung quanh các giới hạn I / O, Bộ nhớ hoặc Cache. Xem các thuật toán lãng quên bộ nhớ cache .


73

Đa luồng

Trong câu trả lời này, tôi sẽ điều tra một trường hợp sử dụng quan trọng để phân biệt giữa công việc bị ràng buộc giữa CPU và IO: khi viết mã đa luồng.

Ví dụ ràng buộc RAM I / O: Vector Sum

Hãy xem xét một chương trình tính tổng tất cả các giá trị của một vectơ:

#define SIZE 1000000000
unsigned int is[SIZE];
unsigned int sum = 0;
size_t i = 0;
for (i = 0; i < SIZE; i++)
    /* Each one of those requires a RAM access! */
    sum += is[i]

Song song với việc bằng cách chia mảng bằng nhau cho mỗi lõi của bạn là hữu ích hạn chế trên các máy tính để bàn hiện đại phổ biến.

Ví dụ: trên Ubuntu 19.04 của tôi, máy tính xách tay Lenovo ThinkPad P51 có CPU: CPU Intel Core i7-7820HQ (4 lõi / 8 luồng), RAM: 2x Samsung M471A2K43BB1-CRC (2x 16GiB) Tôi nhận được kết quả như sau:

nhập mô tả hình ảnh ở đây

Lô dữ liệu .

Lưu ý rằng có rất nhiều phương sai giữa chạy. Nhưng tôi không thể tăng kích thước mảng hơn nữa vì tôi đã ở mức 8GiB và tôi không có tâm trạng thống kê qua nhiều lần chạy ngày hôm nay. Tuy nhiên, điều này có vẻ giống như một lần chạy thông thường sau khi thực hiện nhiều lần chạy thủ công.

Mã điểm chuẩn:

Tôi không biết đủ kiến ​​trúc máy tính để giải thích đầy đủ hình dạng của đường cong, nhưng có một điều rõ ràng: tính toán không trở nên nhanh hơn 8 lần như mong đợi một cách ngây thơ do tôi sử dụng tất cả 8 luồng của mình! Vì một số lý do, 2 và 3 luồng là tối ưu, và thêm nhiều hơn chỉ khiến mọi thứ chậm hơn nhiều.

So sánh điều này với công việc bị ràng buộc bởi CPU, công việc thực sự nhanh hơn 8 lần: 'thực', 'người dùng' và 'sys' nghĩa là gì trong đầu ra của thời gian (1)?

Lý do là tất cả các bộ xử lý chia sẻ một bus bộ nhớ duy nhất liên kết với RAM:

CPU 1   --\    Bus    +-----+
CPU 2   ---\__________| RAM |
...     ---/          +-----+
CPU N   --/

vì vậy bus bộ nhớ nhanh chóng trở thành nút cổ chai chứ không phải CPU.

Điều này xảy ra bởi vì việc thêm hai số mất một chu kỳ CPU, việc đọc bộ nhớ mất khoảng 100 chu kỳ CPU trong phần cứng 2016.

Vì vậy, công việc CPU được thực hiện trên mỗi byte dữ liệu đầu vào quá nhỏ và chúng tôi gọi đây là quá trình liên kết với IO.

Cách duy nhất để tăng tốc tính toán đó hơn nữa, là tăng tốc truy cập bộ nhớ riêng với phần cứng bộ nhớ mới, ví dụ bộ nhớ đa kênh .

Nâng cấp lên đồng hồ CPU nhanh hơn chẳng hạn sẽ không hữu ích lắm.

Những ví dụ khác

  • nhân ma trận được giới hạn CPU trên RAM và GPU. Đầu vào chứa:

    2 * N**2
    

    số, nhưng:

    N ** 3
    

    phép nhân được thực hiện và điều đó là đủ để song song có giá trị đối với N lớn thực tế

    Đây là lý do tại sao các thư viện nhân ma trận CPU song song tồn tại như sau:

    Việc sử dụng bộ nhớ cache tạo ra sự khác biệt lớn đối với tốc độ thực hiện. Xem ví dụ ví dụ so sánh GPU didactic này .

    Xem thêm:

  • Mạng là ví dụ ràng buộc IO nguyên mẫu.

    Ngay cả khi chúng tôi gửi một byte dữ liệu, vẫn cần một thời gian lớn để đến đích.

    Song song với các yêu cầu mạng nhỏ như yêu cầu HTTP có thể mang lại hiệu suất rất lớn.

    Nếu mạng đã hoạt động hết công suất (ví dụ: tải xuống torrent), việc song song hóa vẫn có thể tăng cải thiện độ trễ (ví dụ: bạn có thể tải trang web "cùng một lúc").

  • Một hoạt động ràng buộc CPU C ++ giả có một số và crunch nó rất nhiều:

  • Sắp xếp có vẻ là CPU dựa trên thử nghiệm sau: Đã có thuật toán song song C ++ 17 chưa? cho thấy sự cải thiện hiệu suất gấp 4 lần cho sắp xếp song song, nhưng tôi cũng muốn có một xác nhận lý thuyết hơn

Làm thế nào để tìm ra nếu bạn bị ràng buộc CPU hoặc IO

IO không phải RAM bị ràng buộc như đĩa, mạng : ps aux, sau đó nếu CPU% / 100 < n threads. Nếu có, bạn bị ràng buộc IO, ví dụ: chặn reads chỉ chờ dữ liệu và bộ lập lịch đang bỏ qua quá trình đó. Sau đó sử dụng các công cụ khác như sudo iotopđể quyết định chính xác IO nào là vấn đề.

Hoặc, nếu việc thực thi nhanh chóng và bạn tham số số lượng luồng, bạn có thể thấy nó dễ dàng từ timehiệu suất đó được cải thiện khi số lượng luồng tăng lên cho công việc bị ràng buộc của CPU: 'real', 'user' và 'sys' nghĩa là gì đầu ra của thời gian (1)?

Giới hạn RAM-IO: khó nói hơn, vì thời gian chờ RAM được bao gồm trong CPU%các phép đo, xem thêm:

Một số tùy chọn:

GPU

GPU có một nút cổ chai IO khi bạn lần đầu tiên chuyển dữ liệu đầu vào từ RAM thông thường có thể đọc được CPU sang GPU.

Do đó, GPU chỉ có thể tốt hơn CPU cho các ứng dụng bị ràng buộc CPU.

Tuy nhiên, khi dữ liệu được truyền tới GPU, nó có thể hoạt động trên các byte đó nhanh hơn CPU, bởi vì GPU:

  • có nhiều nội địa hóa dữ liệu hơn hầu hết các hệ thống CPU và vì vậy dữ liệu có thể được truy cập nhanh hơn đối với một số lõi so với các hệ thống khác

  • khai thác song song dữ liệu và hy sinh độ trễ bằng cách bỏ qua bất kỳ dữ liệu nào chưa sẵn sàng để được vận hành ngay lập tức.

    Vì GPU phải hoạt động trên dữ liệu đầu vào song song lớn, tốt hơn là chỉ nên bỏ qua dữ liệu tiếp theo có thể có sẵn thay vì chờ dữ liệu hiện tại có sẵn và chặn tất cả các hoạt động khác như CPU ​​chủ yếu

Do đó, GPU có thể nhanh hơn CPU nếu ứng dụng của bạn:

  • có thể được song song hóa cao: các khối dữ liệu khác nhau có thể được xử lý riêng biệt với nhau
  • yêu cầu số lượng thao tác đủ lớn trên mỗi byte đầu vào (không giống như phép cộng vector chỉ thực hiện một phép cộng cho mỗi byte)
  • có một số lượng lớn các byte đầu vào

Các lựa chọn thiết kế này ban đầu nhắm vào ứng dụng kết xuất 3D, có các bước chính như được hiển thị tại Trình tạo bóng trong OpenGL là gì và chúng ta cần chúng để làm gì?

  • đỉnh shader: nhân một bó vectơ 1x4 với ma trận 4 x 4
  • shader mảnh: tính màu của từng pixel của một tam giác dựa trên vị trí tương đối của nó với tam giác

và vì vậy chúng tôi kết luận rằng các ứng dụng đó bị ràng buộc bởi CPU.

Với sự ra đời của GPGPU có thể lập trình, chúng ta có thể quan sát một số ứng dụng GPGPU đóng vai trò là ví dụ về các hoạt động ràng buộc của CPU:

Xem thêm:

Khóa Intepreter toàn cầu CPython (GIL)

Như một trường hợp nghiên cứu nhanh, tôi muốn chỉ ra Khóa phiên dịch toàn cầu Python (GIL): Khóa trình thông dịch toàn cầu (GIL) trong CPython là gì?

Chi tiết triển khai CPython này ngăn không cho nhiều luồng Python sử dụng hiệu quả công việc gắn với CPU. Các tài liệu CPython nói:

Chi tiết triển khai CPython: Trong CPython, do Khóa phiên dịch toàn cầu, chỉ một luồng có thể thực thi mã Python cùng một lúc (ngay cả khi các thư viện hướng hiệu suất nhất định có thể khắc phục giới hạn này). Nếu bạn muốn ứng dụng của mình sử dụng tốt hơn các tài nguyên tính toán của các máy đa lõi, bạn nên sử dụng multiprocessinghoặc concurrent.futures.ProcessPoolExecutor. Tuy nhiên, luồng vẫn là một mô hình thích hợp nếu bạn muốn chạy đồng thời nhiều tác vụ ràng buộc I / O.

Do đó, ở đây chúng ta có một ví dụ trong đó nội dung giới hạn CPU không phù hợp và ràng buộc I / O.


1
Man, làm thế nào để bạn có thể trở nên có năng lực và viết như thế này?
Mikayil Abdullayev

1
@MikayilAbdullayev cảm ơn! Tôi có xu hướng chỉ trả lời "những câu hỏi quan trọng" và tôi có xu hướng quay lại với chúng nhiều lần khi tôi học những thứ mới có liên quan.
Ciro Santilli 郝海东 冠状 病 事件

31

Giới hạn CPU có nghĩa là chương trình bị tắc nghẽn bởi CPU hoặc đơn vị xử lý trung tâm, trong khi ràng buộc I / O có nghĩa là chương trình bị tắc nghẽn bởi I / O hoặc đầu vào / đầu ra, chẳng hạn như đọc hoặc ghi vào đĩa, mạng, v.v.

Nói chung, khi tối ưu hóa các chương trình máy tính, người ta cố gắng tìm ra nút thắt và loại bỏ nó. Biết rằng chương trình của bạn bị ràng buộc CPU, do đó người ta không cần tối ưu hóa một cái gì đó một cách không cần thiết.

[Và bởi "nút cổ chai", ý tôi là điều khiến chương trình của bạn chậm hơn so với những gì nó có.]


22

Một cách khác để diễn đạt cùng một ý tưởng:

  • Nếu tăng tốc CPU không tăng tốc chương trình của bạn, nó có thể bị ràng buộc I / O.

  • Nếu tăng tốc I / O (ví dụ: sử dụng đĩa nhanh hơn) không có ích, chương trình của bạn có thể bị ràng buộc CPU.

(Tôi đã sử dụng "có thể" vì bạn cần tính đến các tài nguyên khác. Bộ nhớ là một ví dụ.)


11

Khi chương trình của bạn đang chờ I / O (tức là đọc / ghi đĩa hoặc đọc / ghi mạng, v.v.), CPU có thể tự do thực hiện các tác vụ khác ngay cả khi chương trình của bạn bị dừng. Tốc độ của chương trình của bạn chủ yếu sẽ phụ thuộc vào tốc độ IO có thể xảy ra và nếu bạn muốn tăng tốc độ, bạn sẽ cần tăng tốc I / O.

Nếu chương trình của bạn đang chạy nhiều hướng dẫn chương trình và không chờ I / O, thì nó được gọi là bị ràng buộc CPU. Tăng tốc CPU sẽ giúp chương trình chạy nhanh hơn.

Trong cả hai trường hợp, chìa khóa để tăng tốc chương trình có thể không phải là tăng tốc phần cứng, mà là tối ưu hóa chương trình để giảm lượng IO hoặc CPU mà nó cần, hoặc để I / O thực hiện trong khi nó cũng tốn CPU đồ đạc.


6

Ràng buộc I / O đề cập đến một điều kiện trong đó thời gian cần thiết để hoàn thành một tính toán được xác định chủ yếu bởi khoảng thời gian chờ đợi cho các hoạt động đầu vào / đầu ra được hoàn thành.

Điều này ngược lại với một nhiệm vụ bị ràng buộc CPU. Tình huống này phát sinh khi tốc độ yêu cầu dữ liệu chậm hơn tốc độ được tiêu thụ hoặc nói cách khác, dành nhiều thời gian hơn để yêu cầu dữ liệu hơn là xử lý dữ liệu.


6

Các quy trình ràng buộc IO: dành nhiều thời gian hơn để thực hiện IO so với tính toán, có nhiều đợt CPU ngắn. Các quy trình ràng buộc CPU: dành nhiều thời gian hơn cho việc tính toán, một vài lần nổ CPU rất dài


2

Xem những gì Microsoft nói.

Cốt lõi của lập trình async là các đối tượng Nhiệm vụ và Nhiệm vụ, mô hình hóa các hoạt động không đồng bộ. Chúng được hỗ trợ bởi async và đang chờ từ khóa. Mô hình khá đơn giản trong hầu hết các trường hợp:

  • Đối với mã bị ràng buộc I / O, bạn đang chờ một thao tác trả về một Tác vụ hoặc Tác vụ bên trong một phương thức không đồng bộ.

  • Đối với mã giới hạn CPU, bạn chờ đợi một hoạt động được bắt đầu trên một luồng nền với phương thức Task.Run.

Từ khóa đang chờ là nơi phép màu xảy ra. Nó mang lại quyền kiểm soát cho người gọi phương thức đã thực hiện chờ đợi và cuối cùng cho phép UI phản hồi hoặc dịch vụ có thể co giãn.

Ví dụ I / O-Bound: Tải xuống dữ liệu từ dịch vụ web

private readonly HttpClient _httpClient = new HttpClient();

downloadButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI as the request
    // from the web service is happening.
    //
    // The UI thread is now free to perform other work.
    var stringData = await _httpClient.GetStringAsync(URL);
    DoSomethingWithData(stringData);
};

Ví dụ về giới hạn CPU: Thực hiện tính toán cho trò chơi

private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}

calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI while CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};

Các ví dụ ở trên cho thấy cách bạn có thể sử dụng async và chờ đợi cho công việc gắn kết I / O và CPU. Đó là chìa khóa mà bạn có thể xác định khi nào một công việc bạn cần làm là ràng buộc I / O hoặc ràng buộc CPU, bởi vì nó có thể ảnh hưởng lớn đến hiệu suất mã của bạn và có khả năng dẫn đến việc sử dụng sai các cấu trúc nhất định.

Đây là hai câu hỏi bạn nên hỏi trước khi viết bất kỳ mã nào:

Mã của bạn sẽ "chờ" một cái gì đó, chẳng hạn như dữ liệu từ cơ sở dữ liệu?

  • Nếu câu trả lời của bạn là "có", thì công việc của bạn là ràng buộc I / O.

Mã của bạn sẽ được thực hiện một tính toán rất tốn kém?

  • Nếu bạn trả lời "có", thì công việc của bạn bị ràng buộc bởi CPU.

Nếu công việc bạn có là ràng buộc I / O, hãy sử dụng async và chờ đợi mà không có Task.Run . Bạn không nên sử dụng Thư viện song song tác vụ. Lý do cho điều này được nêu trong bài viết Async in Depth .

Nếu công việc bạn có bị ràng buộc bởi CPU và bạn quan tâm đến khả năng đáp ứng, hãy sử dụng async và chờ đợi nhưng sinh ra công việc trên một luồng khác với Task.Run. Nếu công việc phù hợp với tính đồng thời và song song, bạn cũng nên xem xét sử dụng Thư viện song song tác vụ .


2

Một ứng dụng bị ràng buộc bởi CPU khi hiệu năng số học / logic / dấu phẩy động (A / L / FP) trong khi thực hiện hầu hết là gần hiệu suất cao nhất về mặt lý thuyết của bộ xử lý (dữ liệu do nhà sản xuất cung cấp và được xác định bởi các đặc tính của bộ xử lý: số lượng lõi, tần số, thanh ghi, ALU, FPU, v.v.).

Hiệu suất nhìn trộm rất khó đạt được trong các ứng dụng trong thế giới thực, vì không nói là không thể. Hầu hết các ứng dụng truy cập bộ nhớ trong các phần khác nhau của quá trình thực thi và bộ xử lý không thực hiện các hoạt động A / L / FP trong một số chu kỳ. Đây được gọi là Giới hạn Von Neumann do khoảng cách tồn tại giữa bộ nhớ và bộ xử lý.

Nếu bạn muốn ở gần hiệu năng cao nhất của CPU, một chiến lược có thể là cố gắng sử dụng lại hầu hết dữ liệu trong bộ nhớ đệm để tránh yêu cầu dữ liệu từ bộ nhớ chính. Một thuật toán khai thác tính năng này là phép nhân ma trận (nếu cả hai ma trận có thể được lưu trữ trong bộ nhớ đệm). Điều này xảy ra bởi vì nếu ma trận có kích thước n x nthì bạn cần thực hiện các 2 n^3thao tác chỉ sử dụng 2 n^2số dữ liệu FP. Mặt khác, ngoài ra, ma trận là một ứng dụng ít ràng buộc CPU hơn hoặc nhiều bộ nhớ hơn so với phép nhân ma trận vì nó chỉ yêu cầu n^2FLOP với cùng một dữ liệu.

Trong hình dưới đây, các FLOP thu được với thuật toán ngây thơ cho phép cộng ma trận và phép nhân ma trận trong Intel i5-9300H, được hiển thị:

FLOP so sánh giữa phép cộng ma trận và phép nhân ma trận

Lưu ý rằng như mong đợi hiệu suất của phép nhân ma trận lớn hơn phép cộng ma trận. Những kết quả này có thể được sao chép bằng cách chạy test/gemmtest/mataddcó sẵn trong kho lưu trữ này .

Tôi cũng đề nghị xem video do J. Dongarra đưa ra về hiệu ứng này.


1

Quá trình giới hạn I / O: - Nếu phần lớn thời gian tồn tại của một quá trình được sử dụng ở trạng thái i / o, thì quá trình đó là ai / o ràng buộc quy trình. Ví dụ: -calculator, internet explorer

Quá trình giới hạn CPU: - Nếu phần lớn thời gian của quá trình được sử dụng trong cpu, thì đó là quy trình ràng buộc cpu.


8
Làm thế nào máy tính sẽ là một quá trình ràng buộc IO? Chắc chắn nó sẽ bị ràng buộc CPU. Nếu máy tính của bạn dành phần lớn thời gian bị chặn bằng cách truy cập mạng hoặc đĩa thì tôi đề nghị có gì đó không ổn với nó.
rickerbh

6
Tôi nghĩ rằng ví dụ về máy tính rất rõ ràng: hầu hết thời gian chờ đợi của người dùng để nhấn nút, do đó chờ cho I / O.
psp

1
@psp đúng nhưng ví dụ về máy tính vẫn rất khó nhìn vì bị ràng buộc bởi vì tên của nó là "máy tính". Điều đó ngụ ý rằng mục đích chính của chương trình là thực hiện các phép tính cpu dài, nhưng nếu bạn nhìn vào máy tính của mình trên máy tính để bàn thì đó là một cách rất đơn giản chỉ thực hiện các phép tính mất vài nano giây. Do đó, hầu hết thời gian nó chờ đợi đầu vào của người dùng, đó là IO.
Calicoder
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.