◆ 概要
本文中,筆者為 《簡單的線程池(四)》 提及的非阻塞獨占式線程池增加了一項功能:當某個工作線程的任務隊列中無工作任務時,此工作線程可以去其他工作線程的任務隊列中獲取任務。筆者稱之為非阻塞互助式線程池。
筆者對比了測試結果與 《簡單的線程池(六)》 的數據,得出了添加功能前后的差異。
本文不再贅訴與 《簡單的線程池(四)》 相同的內容。如有不明之處,請參考該博客。
◆ 實現
以下代碼給出了此線程池的實現,(lockwise_mutual_pool.h)
class Thread_Pool {
private:
struct Task_Wrapper { ...
};
atomic<bool> _suspend_;
atomic<bool> _done_;
unsigned _workersize_;
thread* _workers_;
Lockwise_Queue<Task_Wrapper>* _workerqueues_;
void work(unsigned index) {
Task_Wrapper task;
while (!_done_.load(memory_order_acquire)) {
if (_workerqueues_[index].pop(task))
task();
else // # 1
for (unsigned i = 0; i < _workersize_; ++i)
if (_workerqueues_[(index + i + 1) % _workersize_].pop(task)) { // #2
task();
break;
}
while (_suspend_.load(memory_order_acquire))
std::this_thread::yield();
}
}
void stop() { ...
}
public:
Thread_Pool() : _suspend_(false), _done_(false) { ....
}
~Thread_Pool() { ...
}
template<class Callable>
future<typename std::result_of<Callable()>::type> submit(Callable c) { ...
}
};
此線程池的代碼與 非阻塞獨占式線程池 相比,僅在工作線程的初始函數 Thread_Pool::work(unsigned) 上有區別。當某個工作線程的任務隊列中無工作任務時(#1),此工作線程會去其他工作線程的任務隊列中獲取任務。這里涉及到的“選擇其他工作線程的任務隊列的算法”(#2),來自於本文最后的參考書籍。
◆ 邏輯
此線程池的結構和與 《簡單的線程池(四)》 中的一致,此處略。
此線程池用戶提交任務與工作線程執行任務的並發過程與 《簡單的線程池(一)》 中的一致,此處略。
◆ 驗證
驗證過程采用了 《簡單的線程池(三)》 中定義的的測試用例。筆者對比了測試結果與 《簡單的線程池(六)》 的數據,結果如下,
圖1 列舉了 吞吐量1的差異 在 0.5 分鍾、1 分鍾和 3 分鍾的提交周期內不同思考時間上的對比。
【注】非阻塞互助式 略稱為 LM ,下同。
可以看到,
- 當思考時間為 0 時,LM 的吞吐量優於 LS、BS 的吞吐量,相當於 LU、BU 的吞吐量;延長提交周期后,LM 和 LS、BS、LU、BU 的吞吐量差異沒有發生明顯變化;
- 當思考時間不為 0 時,LM 的吞吐量大幅優於 LS、LU 的吞吐量,大幅劣於 BS、BU 的吞吐量,但差異不會因提交周期的延長而大幅變化;隨着思考時間的增加,LM 的吞吐量與 LS、BS、LU、BU 的吞吐量差異逐漸消失。
圖2 列舉了 吞吐量2的差異 在 0.5 分鍾、1 分鍾和 3 分鍾的提交周期內不同思考時間上的對比。
可以看到,
- 當思考時間為 0 時,LM 的吞吐量優於 LS、BS、LU、BU 的吞吐量;延長提交周期后,LM 和 LS、BS、LU、BU 的吞吐量差異沒有發生明顯變化;
- 當思考時間不為 0 時,因 LM 和 LS、BS、LU、BU 的吞吐量均為 0,它們間沒有差異。
圖3 列舉了 吞吐量3的差異 在 0.5 分鍾、1 分鍾和 3 分鍾的提交周期內不同思考時間上的對比。
可以看到,
- 當思考時間為 0 時,LM 的吞吐量相當於 LS、BS、LU 的吞吐量,略劣於 BU 的吞吐量;延長提交周期后,LM 和 LS、BS、LU、BU 的吞吐量差異沒有發生明顯變化;
- 當思考時間不為 0 時,LM 的吞吐量大幅優於 LS、LU 的吞吐量,大幅劣於 BS、BU 的吞吐量,但差異不會因提交周期的延長而大幅變化;隨着思考時間的增加,LM 的吞吐量與 LS、BS、LU、BU 的吞吐量差異逐漸消失。
基於以上的對比分析,筆者認為,在非阻塞式線程池中,
- 互助式的吞吐量指標優於共享式、獨占式的吞吐量指標。
◆ 最后
完整的示例代碼和測試結果請參考 [github] cnblogs/15710614 。
關於“選擇其他工作線程的任務隊列的算法”,筆者參考了 C++並發編程實戰 / (美)威廉姆斯 (Williams, A.) 著; 周全等譯. - 北京: 人民郵電出版社, 2015.6 (2016.4重印) 一書。致 Anthony Williams、周全等譯者。