Nó có liên quan lỏng lẻo đến câu hỏi này: Std :: thread có được gộp chung trong C ++ 11 không? . Mặc dù câu hỏi khác nhau, mục đích là giống nhau:
Câu hỏi 1: Sử dụng nhóm luồng của riêng bạn (hoặc thư viện bên thứ 3) để tránh tạo luồng tốn kém có còn hợp lý không?
Kết luận trong câu hỏi khác là bạn không thể dựa vào std::thread
để được gộp (có thể có hoặc có thể không). Tuy nhiên, std::async(launch::async)
có vẻ như cơ hội được gộp cao hơn nhiều.
Nó không nghĩ rằng nó bị buộc bởi tiêu chuẩn, nhưng IMHO, tôi hy vọng rằng tất cả các triển khai C ++ 11 tốt sẽ sử dụng tổng hợp luồng nếu quá trình tạo luồng chậm. Chỉ trên các nền tảng không tốn kém để tạo một luồng mới, tôi mong rằng chúng luôn sinh ra một luồng mới.
Câu hỏi 2: Đây chỉ là những gì tôi nghĩ, nhưng tôi không có dữ kiện để chứng minh điều đó. Tôi rất có thể đã nhầm. Nó có phải là một phỏng đoán có học không?
Cuối cùng, ở đây tôi đã cung cấp một số mã mẫu đầu tiên cho thấy cách tôi nghĩ rằng việc tạo luồng có thể được thể hiện bằng async(launch::async)
:
Ví dụ 1:
thread t([]{ f(); });
// ...
t.join();
trở thành
auto future = async(launch::async, []{ f(); });
// ...
future.wait();
Ví dụ 2: Cháy và quên chuỗi
thread([]{ f(); }).detach();
trở thành
// a bit clumsy...
auto dummy = async(launch::async, []{ f(); });
// ... but I hope soon it can be simplified to
async(launch::async, []{ f(); });
Câu hỏi 3: Bạn thích async
phiên thread
bản nào hơn phiên bản?
Phần còn lại không còn là một phần của câu hỏi, mà chỉ để làm rõ:
Tại sao giá trị trả về phải được gán cho một biến giả?
Thật không may, tiêu chuẩn C ++ 11 hiện tại buộc bạn phải nắm bắt giá trị trả về std::async
, vì nếu không, trình hủy được thực thi, sẽ chặn cho đến khi hành động kết thúc. Nó được một số người coi là một lỗi trong tiêu chuẩn (ví dụ, bởi Herb Sutter).
Ví dụ này từ cppreference.com minh họa điều đó một cách độc đáo:
{
std::async(std::launch::async, []{ f(); });
std::async(std::launch::async, []{ g(); }); // does not run until f() completes
}
Làm rõ khác:
Tôi biết rằng nhóm luồng có thể có những cách sử dụng hợp pháp khác nhưng trong câu hỏi này tôi chỉ quan tâm đến khía cạnh tránh chi phí tạo luồng đắt đỏ .
Tôi nghĩ rằng vẫn có những tình huống mà nhóm luồng rất hữu ích, đặc biệt nếu bạn cần kiểm soát nhiều hơn đối với tài nguyên. Ví dụ: máy chủ có thể quyết định chỉ xử lý đồng thời một số lượng yêu cầu cố định để đảm bảo thời gian phản hồi nhanh và tăng khả năng dự đoán của việc sử dụng bộ nhớ. Nhóm chủ đề sẽ ổn, ở đây.
Biến cục bộ của luồng cũng có thể là một đối số cho nhóm luồng của riêng bạn, nhưng tôi không chắc liệu nó có liên quan trong thực tế hay không:
- Tạo một luồng mới với sự
std::thread
bắt đầu mà không có biến cục bộ của luồng được khởi tạo. Có thể đây không phải là điều bạn muốn. - Trong các chủ đề được sinh ra bởi
async
, tôi hơi không rõ ràng vì chủ đề đó có thể đã được sử dụng lại. Theo hiểu biết của tôi, các biến cục bộ của luồng không được đảm bảo sẽ được đặt lại, nhưng tôi có thể nhầm. - Mặt khác, việc sử dụng nhóm luồng (kích thước cố định) của riêng bạn, cho phép bạn toàn quyền kiểm soát nếu bạn thực sự cần.
std::async()
. Tôi vẫn tò mò muốn biết cách họ hỗ trợ các trình hủy thread_local không tầm thường trong nhóm luồng.
launch::async
thì nó sẽ xử lý nó như thể nó duy nhất launch::deferred
và không bao giờ thực thi nó một cách không đồng bộ - vì vậy, trên thực tế, phiên bản đó của libstdc ++ "chọn" luôn sử dụng hoãn lại trừ khi bị ép buộc khác.
std::async
có thể là một điều tuyệt vời cho hiệu suất - nó có thể là hệ thống thực thi nhiệm vụ ngắn hạn tiêu chuẩn, được hỗ trợ tự nhiên bởi một nhóm luồng. Ngay bây giờ, nó chỉ là một std::thread
với một số thứ vớ vẩn để làm cho hàm luồng có thể trả về một giá trị. Ồ, và họ đã thêm chức năng "hoãn lại" dư thừa chồng chéo công việc của std::function
hoàn toàn.
std::async(launch::async)
có vẻ như cơ hội được gộp cao hơn nhiều." Không, tôi tin rằng nóstd::async(launch::async | launch::deferred)
có thể được gộp lại. Chỉlaunch::async
với nhiệm vụ được cho là được khởi chạy trên một luồng mới bất kể những tác vụ khác đang chạy. Với chính sáchlaunch::async | launch::deferred
thì việc triển khai sẽ phải chọn chính sách nào, nhưng quan trọng hơn là phải trì hoãn việc lựa chọn chính sách nào. Nghĩa là, nó có thể đợi cho đến khi một luồng trong nhóm luồng khả dụng và sau đó chọn chính sách không đồng bộ.