Làm thế nào để lập trình phân bổ luồng trên bộ xử lý đa lõi?


13

Tôi muốn thử nghiệm các luồng trên bộ xử lý đa lõi, ví dụ để tạo một chương trình sử dụng hai luồng khác nhau được thực thi bởi hai lõi bộ xử lý khác nhau.

Tuy nhiên, tôi không rõ các cấp độ được phân bổ cho các lõi khác nhau ở cấp độ nào. Tôi có thể tưởng tượng các tình huống sau (tùy thuộc vào hệ điều hành và triển khai ngôn ngữ lập trình):

  1. Phân bổ luồng được quản lý bởi hệ điều hành. Các luồng được tạo bằng các lệnh gọi hệ điều hành và, nếu quá trình xảy ra để chạy trên bộ xử lý đa lõi, HĐH sẽ tự động cố gắng phân bổ / lên lịch các luồng khác nhau trên các lõi khác nhau.
  2. Phân bổ luồng được quản lý bởi việc thực hiện ngôn ngữ lập trình. Phân bổ các luồng cho các lõi khác nhau đòi hỏi các cuộc gọi hệ thống đặc biệt, nhưng các thư viện luồng tiêu chuẩn của ngôn ngữ lập trình sẽ tự động xử lý việc này khi tôi sử dụng triển khai luồng tiêu chuẩn cho ngôn ngữ đó.
  3. Phân bổ chủ đề phải được lập trình rõ ràng. Trong chương trình của tôi, tôi phải viết mã rõ ràng để phát hiện có bao nhiêu lõi có sẵn và phân bổ các luồng khác nhau cho các lõi khác nhau bằng cách sử dụng, ví dụ, các hàm thư viện.

Để làm cho câu hỏi cụ thể hơn, hãy tưởng tượng tôi đã viết ứng dụng đa luồng của mình bằng Java hoặc C ++ trên Windows hoặc Linux. Ứng dụng của tôi sẽ thấy và sử dụng nhiều lõi một cách kỳ diệu khi chạy trên bộ xử lý đa lõi (bởi vì mọi thứ được quản lý bởi hệ điều hành hoặc thư viện luồng tiêu chuẩn), hoặc tôi phải sửa đổi mã của mình để nhận biết nhiều lõi ?

Câu trả lời:


11

Ứng dụng của tôi sẽ thấy và sử dụng nhiều lõi một cách kỳ diệu khi chạy trên bộ xử lý đa lõi (bởi vì mọi thứ được quản lý bởi hệ điều hành hoặc thư viện luồng tiêu chuẩn), hoặc tôi phải sửa đổi mã của mình để nhận biết nhiều lõi ?

Câu trả lời đơn giản: Có, nó thường sẽ được quản lý bởi hệ điều hành hoặc thư viện luồng.

Hệ thống con luồng trong hệ điều hành sẽ gán luồng cho bộ xử lý trên cơ sở ưu tiên (tùy chọn 1 của bạn). Nói cách khác, khi một luồng đã thực hiện xong việc phân bổ thời gian hoặc các khối của nó, bộ lập lịch tìm kiếm luồng ưu tiên cao nhất tiếp theo và gán nó cho CPU. Các chi tiết khác nhau từ hệ điều hành để hệ điều hành.

Điều đó nói rằng, các tùy chọn 2 (được quản lý bởi ngôn ngữ lập trình) và 3 (rõ ràng) tồn tại. Ví dụ: thư viện Tác vụ và async / await trong các phiên bản gần đây của .Net cung cấp cho nhà phát triển một cách dễ dàng hơn để viết mã song song (nghĩa là có thể chạy đồng thời với chính mã). Các ngôn ngữ lập trình chức năng là song song bẩm sinh và một số thời gian chạy sẽ chạy song song các phần khác nhau của chương trình nếu có thể.

Đối với tùy chọn 3 (rõ ràng), Windows cho phép bạn đặt mối quan hệ luồng (chỉ định bộ xử lý nào mà luồng có thể chạy). Tuy nhiên, điều này thường không cần thiết trong tất cả, trừ các hệ thống quan trọng nhất, thời gian đáp ứng nhanh nhất. Phân luồng hiệu quả để phân bổ bộ xử lý phụ thuộc nhiều vào phần cứng và rất nhạy cảm với các ứng dụng khác chạy đồng thời.

Nếu bạn muốn thử nghiệm, hãy tạo một tác vụ chuyên sâu, chạy CPU trong thời gian dài như tạo danh sách các số nguyên tố hoặc tạo bộ Mandelbrot. Bây giờ tạo hai luồng trong thư viện yêu thích của bạn và chạy cả hai luồng trên máy đa bộ xử lý (nói cách khác, chỉ là về bất cứ thứ gì được phát hành trong vài năm qua). Cả hai nhiệm vụ nên hoàn thành trong cùng một khoảng thời gian vì chúng được chạy song song.


Cảm ơn đã giải thích (+1). Chương trình thử nghiệm của tôi là một thực hiện sắp xếp hợp nhất. Trong giai đoạn phân tách, tôi muốn tạo các luồng khác nhau miễn là có sẵn các lõi. Ví dụ, với hai lõi, mỗi nửa của một mảng sẽ được sắp xếp theo một luồng / lõi khác nhau. Trong quá trình hợp nhất, các luồng thừa sẽ được nối / kết thúc.
Giorgio

Sắp xếp rất khó để song song theo cách này nếu dữ liệu được phân phối ngẫu nhiên. Vâng, bạn có thể chia nó ra sau đó sắp xếp từng phần trong một luồng khác nhau nhưng cuối cùng bạn phải hợp nhất tất cả các phần lại với nhau. Nếu các luồng đang chia sẻ cấu trúc dữ liệu, bạn cũng có thể gặp sự cố tranh chấp hoặc khóa. Tôi không nói rằng sắp xếp không thể có lợi từ luồng nhưng nó sẽ không phải là một cải tiến hiệu suất tuyến tính.
akton

Hai nửa của một mảng có thể được sắp xếp độc lập vì không có dữ liệu nào được chia sẻ. Chỉ phân tách đầu tiên và hợp nhất cuối cùng sẽ phải được thực hiện bởi một luồng thao tác trên toàn bộ mảng hoặc danh sách chứa dữ liệu. Điều này có nghĩa là một lần quét hoàn toàn dữ liệu không thể được thực hiện song song; tất cả các lần quét còn lại có thể.
Giorgio

Tất nhiên, tôi cũng coi ví dụ của bạn là ứng cử viên tốt. Tôi chỉ quen thuộc hơn với sắp xếp hợp nhất tại thời điểm này (và tôi đã triển khai một phiên bản không song song của nó), điều này sẽ (có thể) làm cho sắp xếp hợp nhất phù hợp hơn với tôi như một nỗ lực đầu tiên.
Giorgio

2
Tôi sẽ thêm vào câu trả lời này rằng các hệ điều hành tốt đủ thông minh để cân bằng chi phí đưa ra một tác vụ cắt giảm thời gian trên một CPU hoặc lõi khác với việc bỏ đói ngắn hạn. Trên các kiến ​​trúc nơi nó quan trọng, kết quả có xu hướng giống với ái lực tự động. Hệ điều hành đã được xây dựng để giúp tất cả các công việc chạy càng nhanh càng tốt, và bạn có thể tự bắn vào chân mình bằng cách buộc các sợi chỉ vào lõi và cản trở khả năng đưa ra các quyết định đó.
Blrfl

-1

Tôi đã từng có một môi trường SGI IRIX rất lớn. Chỉ vì điều đó, tôi đã viết một chương trình java đa luồng nhỏ (không làm gì ngoài việc tiêu thụ chu kỳ CPU) và tạo ra 12 luồng trong đó. Công việc kéo dài trên 12 CPU trong kiến ​​trúc NUMA. Có thể tôi sẽ tra cứu chương trình và chạy nó trên Dell R910s và kiểm tra ..


3
Câu trả lời này thực sự không thêm nhiều vào câu trả lời hiện có. Có lẽ nếu bạn giải thích lý do tại sao JVM trên hệ thống SGI lại phân bổ các luồng cho lõi ...
Jay Elston
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.