C++11 线程池简单实现以及测试
话不多说,先上代码
//threadpool.h
#pragma once
#include<vector>
#include<queue>
#include<thread>
#include<iostream>
#include<stdexcept>
#include<condition_variable>
#include<memory>
#include<functional>
const int MAX_THREADS = 1000;
typedef std::function<void(void)> Task;
int num = 0;
class threadPool
{
public:
threadPool(int number = 1);
~threadPool();
bool append(Task task);
private:
static void* worker(void* arg);
void run();
private:
std::vector<std::thread> work_threads;
std::queue<Task> tasks_queue;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
threadPool::threadPool(int number) : stop(false)
{
if (number <= 0 || number > MAX_THREADS) {
throw std::exception();
}
for (int i = 0; i < number; i++) {
//std::cout << "创建第" << i << "个进程" << std::endl;
work_threads.emplace_back(threadPool::worker, this);
}
}
inline threadPool::~threadPool()
{
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
condition.notify_all();
for (auto& ww : work_threads)
ww.join();
}
}
bool threadPool::append(Task task)
{
queue_mutex.lock();
tasks_queue.push(task);
queue_mutex.unlock();
condition.notify_one();
return true;
}
void* threadPool::worker(void* arg)
{
threadPool* pool = (threadPool*)arg;
pool->run();
return pool;
}
void threadPool::run()
{
while (!stop) {
std::unique_lock<std::mutex> lk(this->queue_mutex);
//queue_mutex.lock();
this->condition.wait(lk, [this] {return !this->tasks_queue.empty(); });
if (this->tasks_queue.empty()) {
continue;
}
else {
Task task = tasks_queue.front();
tasks_queue.pop();
lk.unlock();
//在获取到任务队列的任务之后,应该马上解锁任务队列,再执行这个任务
task();
}
}
}
主要测试task的个数和所开线程数对完成时间的影响。
测试代码中task是计算密集型任务:for循环累加。代码如下:
#include <iostream>
#include"threadpool.h"
#include<Windows.h>
using namespace std;
int show_res = 0;
mutex data_mutex;
class Test
{
public:
void process_no_static_bind(const int i, const int j) {
int res = 0;
for (int n = 0; n < 50000000; n++) {
res += (i + j);
}
//Sleep(500);
unique_lock<mutex> lk(data_mutex);
show_res++;
//cout << show_res << endl;
}
};
int main() {
threadPool pool(1);
int test_num = 100;
Test tt_bind;
time_t start, end;
start = GetTickCount64();
/* while (true) {
pool.append(std::bind(&Test::process_no_static_bind, &tt_bind, 3, 4));
}*/
cout << "start tag=" << show_res << endl;
for (int i = 0; i < test_num; i++) {
pool.append(std::bind(&Test::process_no_static_bind, &tt_bind, i, 4));
//tt_bind.process_no_static_bind(i, 4);
}
while (show_res < test_num-1) {
Sleep(10);
}
cout << "end tag=" << show_res << endl;
end = GetTickCount64();
cout << "spend time:" << end - start << "mileseconds" << endl;
exit(0);
}
测试结果说明:
测试一:
执行任务数:10
进程数 | 时间 |
---|---|
10 | 1203ms |
9 | 1078ms |
8 | 1329ms |
7 | 1250ms |
6 | 1484ms |
5 | 1359ms |
4 | 1765ms |
3 | 1266ms |
2 | 1984ms |
1 | 3547ms |
测试二:
在每一个任务中添加一个Sleep(100);
执行任务数:10
进程数 | 时间 |
---|---|
10 | 1281ms |
9 | 1265ms |
8 | 1563ms |
7 | 1563ms |
6 | 1547ms |
5 | 1421ms |
4 | 1765ms |
3 | 1578ms |
2 | 2485ms |
1 | 4453ms |
结合测试一和测试二
有一个猜想:单进程执行完所有任务的时间除以核心数(本次为4)约等于多个线程同时执行任务所需的时间。
所以并不是线程越多,执行的速度越快。
同时还需要考虑到是CPU密集型还是IO密集型
CPU密集型的测试:在任务中执行大量的计算或者循环任务
IO密集型的测试:在任务中使用Sleep()函数阻塞
测试三:
CPU密集型:
执行任务数:10
进程数 | 时间 |
---|---|
10 | 1156ms |
9 | 1125ms |
8 | 1531ms |
7 | 1453ms |
6 | 1515ms |
5 | 1235ms |
4 | 1703ms |
3 | 1406ms |
2 | 2125ms |
1 | 3641ms |
测试四:
IO密集型:
执行任务数:10
进程数 | 时间 |
---|---|
10 | 625ms |
9 | 640ms |
8 | 1141ms |
7 | 1109ms |
6 | 1140ms |
5 | 1140ms |
4 | 1719ms |
3 | 1719ms |
2 | 2719ms |
1 | 4984ms |
IO密集型在线程较多的情况下执行速度比CPU密集型要高效
这是因为CPU密集型受制于CPU的核心数,因为任务需要占用的CPU核心数有限,超过核心数的线程不会同时执行
而IO密集型对CPU依赖较小,在一个线程等待IO结果时,其它线程可以继续使用CPU
CPU密集型对CPU依赖较大,在一个线程等待CPU结果时,其它线程不能继续使用CPU
所以对于IO密集型来说,同时使用和任务数相近的线程数可以提高执行速度
测试五:
IO密集型:
执行任务数:100
进程数 | 时间 |
---|---|
10 | 5062ms |
20 | 2563ms |
50 | 1078ms |
100 | 641ms |
200 | 640ms |
由测试五的结果中可以看出,对于IO密集型的任务来说,超过CPU核心数的线程数对于执行速度有较大的提升
因为多线程的使用,使得每个线程在等待IO结果的时间段内CPU可以被其它的线程使用。
测试六:
CPU密集型:
执行任务数:100
进程数 | 时间 |
---|---|
10 | 5672ms |
20 | 5766ms |
50 | 5250ms |
100 | 5062ms |
200 | 5031ms |
4 | 8047ms |
1 | 19172ms |
由测试六的结果中可以看出,对于CPU密集型的任务来说,超过CPU核心数的线程数对于执行速度提升不大
可能有的一点速度提升是在多线程时,执行此任务集合的线程数在系统中的比例较大,使的使用CPU的比例也提高
由此造成的其它进程任务使用CPU的时间被挤占,执行50以上线程时,可以明显看到鼠标反应速度下降
而且线程之间的切换也需要消耗时间