Điểm để sử dụng từ edulcorant. :)
Sự cố với mã mẫu của bạn là bạn đóng gói mọi thứ thành công việc, nhưng bạn không bao giờ lên lịch các tác vụ đó để thực thi!
int calculate_the_answer_to_life() { ... }
int calculate_the_answer_to_death() { ... }
std::packaged_task<int()> pt(calculate_the_answer_to_life);
std::future<int> fi = pt.get_future();
std::packaged_task<int()> pt2(calculate_the_answer_to_death);
std::future<int> fi2 = pt2.get_future();
int calculate_barzoom(std::future<int>& a, std::future<int>& b)
{
boost::wait_for_all(a, b);
return a.get() + b.get();
}
std::packaged_task<int()> pt_composite([]{ return calculate_barzoom(fi, fi2); });
std::future<int> fi_composite = pt_composite.get_future();
Nếu vào thời điểm này tôi viết
pt_composite();
int result = fi_composite.get();
chương trình của tôi sẽ chặn vĩnh viễn. Nó sẽ không bao giờ hoàn tất, vì pt_composite
bị chặn trên calculate_barzoom
, được chặn trên wait_for_all
, mà bị chặn trên cả fi
và fi2
, không ai trong số đó sẽ không bao giờ hoàn thành cho đến khi ai đó thực hiện pt
hoặc pt2
tương ứng. Và không ai sẽ thực hiện chúng, bởi vì chương trình của tôi bị chặn!
Bạn có thể có nghĩa là tôi phải viết một cái gì đó như thế này:
std::async(pt);
std::async(pt2);
std::async(pt_composite);
int result = fi_composite.get();
này sẽ làm việc. Nhưng nó cực kỳ kém hiệu quả - chúng tôi sinh ra ba luồng công nhân (thông qua ba cuộc gọi đến async
), để thực hiện công việc của hai chủ đề. Chủ đề thứ ba - luồng đang chạy pt_composite
- sẽ được sinh ra ngay lập tức và sau đó chỉ cần ngồi đó ngủ cho đến pt
và pt2
đã kết thúc chạy.Đó là tốt hơn so với quay nhưng thấp hơn đáng kể so với không tồn tại: điều đó có nghĩa là nhóm luồng của chúng tôi có ít nhân viên hơn mức cần phải có. Trong một cài đặt pool-pool hợp lý chỉ với một luồng cho mỗi lõi CPU, và rất nhiều nhiệm vụ đến trong mọi lúc, điều đó có nghĩa là chúng ta có một lõi CPU chỉ đang ngồi nhàn rỗi, bởi vì chuỗi công nhân là có nghĩa là đang chạy trên lõi đó hiện bị chặn bên trong wait_for_all
.
Những gì chúng ta muốn làm là tuyên bố ý định của chúng tôi khai báo:
int calculate_the_answer_to_life() { ... }
int calculate_the_answer_to_death() { ... }
std::future<int> fi = std::async(calculate_the_answer_to_life);
std::future<int> fi2 = std::async(calculate_the_answer_to_death);
std::future<int> fi_composite = std::when_all(fi, fi2).then([](auto a, auto b) {
assert(a.is_ready() && b.is_ready());
return a.get() + b.get();
});
int result = fi_composite.get();
và sau đó có thư viện và các công việc lên lịch với nhau để Do The Right Thing: không đẻ trứng bất kỳ sợi nhân mà có thể' t ngay lập tức tiến hành nhiệm vụ của nó. Nếu người dùng cuối phải viết ngay cả một dòng mã rõ ràng ngủ, chờ hoặc chặn, một số hiệu suất chắc chắn sẽ bị mất.
Nói cách khác: Không hiển thị chủ đề công nhân trước thời gian của nó.
Rõ ràng đó là thể để làm tất cả điều này trong tiêu chuẩn C++, không nơi nương tựa thư viện; đó là cách chính thư viện được triển khai! Nhưng đó là một nỗi đau rất lớn để thực hiện từ đầu, với nhiều cạm bẫy tinh tế; vì vậy đó là lý do tại sao nó là một điều tốt mà hỗ trợ thư viện dường như đến sớm.
Đề xuất ISO N3428 được đề cập trong Roshan Shariff's answer đã được cập nhật thành N3857 và N3865 cung cấp nhiều chức năng tiện lợi hơn nữa.
chúng tôi đã có các chức năng có thể tiếp tục làm thư viện tăng: xem 'boost :: context'. việc thực hiện một thư viện 'when_all' sẽ là một số biến thể mẫu variadic của ví dụ mã tôi đã đăng? hoặc là có một số phép thuật mà tôi đang bỏ lỡ? – lurscher
Tất nhiên, tất cả những packaged_tasks cần phải được gửi tại một số điểm đến một hồ bơi thread hoặc 'asio :: io_service' để thực thi async, nhưng ngữ nghĩa không nên bị ảnh hưởng nếu/khi các tính toán được thực hiện – lurscher
@lurscher Thực hiện' when_any' chỉ trên các tính năng thư viện hiện có là có thể, nhưng không nhất thiết phải hiệu quả. Tôi không thể nhìn thấy bất kỳ cách nào để làm điều đó mà không sinh ra một số lượng lớn các chủ đề, ngăn chặn chúng trên tất cả, và chờ đợi cho một trong số họ thức dậy. Mặt khác, nếu hệ điều hành cung cấp một số hỗ trợ, có thể có khả năng thực hiện hiệu quả hơn nhiều cho một nhà cung cấp thư viện chuẩn. –