实验设备CPU(i7-7700 3.6GHz, 4核),内存16G,操作系统Ubuntu 18.04,IDE CLion。
经过代码运行计时,得到以下的实验结果表格。
运行时间/秒 |
2000万 |
5000万 |
1亿 |
1核 |
6.72747 |
25.1391 |
76.2641 |
2核 |
3.36834 |
10.3938 |
27.2989 |
3核 |
2.39181 |
7.15399 |
17.0872 |
4核 |
2.01613 |
5.69332 |
13.0158 |
8核 |
2.09013 |
5.49922 |
11.2955 |
加速比 |
2000万 |
5000万 |
1亿 |
1核 |
1 |
1 |
1 |
2核 |
1.99726572 |
2.41866305 |
2.79366934 |
3核 |
2.81271088 |
3.51399708 |
4.46322979 |
4核 |
3.33682352 |
4.41554313 |
5.85934787 |
8核 |
3.21868496 |
4.57139376 |
6.75172414 |
绘制成图表,如下图所示。
从实验结果和加速比可以看出:
1 随着数据量的增大,快排所需的时间也相应增加;
2 在4核并行内,快排运行的加速比与运行的核心近似成正比;虽然系统显示为8核,但只有4个真正的核。所以当并行线程数大于4后,快排提升的效果并不明显,因为要进行线程的切换。
initVector.cpp
#include "iostream"
#include "fstream"
#include "random"
#include "vector"
#include "string"
#include "sstream"
#include "cstdlib"
using namespace std;
const int size = 20000000;
string path = "/home/dadan/Downloads/vector.txt";
void writeAndInitVector(int size) {
vector res(size, 0.0);
default_random_engine engine;
uniform_real_distribution u(0.0, 20000);
for (int i = 0; i < size; ++i) {
res[i] = u(engine);
}
ofstream outfile(path);
for (int i = 0; i < size; ++i) {
outfile << res[i] << endl;
}
outfile.close();
}
void loadVector(int size) {
vector res(size, 0);
ifstream file(path);
string line;
for (int i = 0; i < size; ++i) {
getline(file, line);
res[i] = stod(line);
}
file.close();
}
int main() {
writeAndInitVector(size);
//loadVector(size);
return 0;
}
quickSort.cpp
#include
#include "pthread.h"
#include "vector"
#include "fstream"
#include "cstring"
#include "climits"
#include "chrono"
#include "ctime"
using namespace std;
using namespace std::chrono;
const long SIZE = 20000000; //the size of vector that need to be sorted
const int THREADS_NUM = 3; // the number of threads
long sortNumPerThread = SIZE / THREADS_NUM; // the number of vector that every thread needs to sort
string path = "/home/dadan/Downloads/vector.txt"; // file path of vector
vector vec(SIZE), sortedVec(SIZE);
pthread_barrier_t barrier;
class Section{
public:
int left;
int right;
Section(){
};
};
void loadVector();
void quickSort(int left, int right);
void *pthread_sort(void *arg);
void merge();
void serial_quick_sort();
int main() {
//serial_quick_sort();
loadVector();
pthread_t tid;
pthread_barrier_init(&barrier, NULL, THREADS_NUM + 1);
auto start = system_clock::now();
for (int i = 0; i < THREADS_NUM; ++i) {
Section* section = new Section;
section->left = i * sortNumPerThread;
if (i == THREADS_NUM - 1) {
section->right = SIZE - 1;
} else {
section->right = (i + 1) * sortNumPerThread - 1;
}
int status = pthread_create(&tid, NULL, pthread_sort, (void *) (section));
if (status != 0) {
cout << "create thread error" << endl;
return -1;
}
}
//main thread wait
pthread_barrier_wait(&barrier);
//merge results of per thread
merge();
auto end = system_clock::now();
auto duration = duration_cast(end - start);
cout << THREADS_NUM << " threads pthread-parallel quick sort takes "
<< double(duration.count()) * microseconds::period::num / microseconds::period::den << " seconds" << endl;
return 0;
}
void loadVector() {
ifstream read_file(path);
string line;
for (int i = 0; i < SIZE; ++i) {
getline(read_file, line);
vec[i] = stod(line);
}
read_file.close();
}
void quickSort(int start, int end) {
if (start >= end)
return;
double base = vec[end];
int left = start, right = end - 1;
while (true) {
while (vec[left] < base)
++left;
while (vec[right] >= base)
--right;
if (left >= right)
break;
swap(vec[left], vec[right]);
}
if (vec[left] >= vec[end])
swap(vec[left], vec[end]);
else
++left;
quickSort(start, left - 1);
quickSort(left + 1, end);
}
void merge() {
vector index(THREADS_NUM), index_most(THREADS_NUM);
for (int i = 0; i < THREADS_NUM; ++i) {
index[i] = i * sortNumPerThread;
if (i == THREADS_NUM - 1) {
index_most[i] = SIZE;
} else {
index_most[i] = (i + 1) * sortNumPerThread;
}
}
for (int i = 0; i < SIZE; ++i) {
int min_index;
double min_num = INT_MAX;
for (int j = 0; j < THREADS_NUM; ++j) {
if ((index[j] < (j + 1) * sortNumPerThread) && (vec[index[j]] < min_num)) {
min_num = vec[index[j]];
min_index = j;
}
}
sortedVec[i] = vec[index[min_index]];
index[min_index]++;
}
}
void serial_quick_sort() {
loadVector();
auto start = system_clock::now();
quickSort(0, SIZE - 1);
auto end = system_clock::now();
auto duration = duration_cast(end - start);
cout << "serial quick sort takes "
<< double(duration.count()) * microseconds::period::num / microseconds::period::den << " seconds" << endl;
}
void *pthread_sort(void *arg) {
Section* section = (Section*)arg;
quickSort(section->left, section->right);
//wait other threads
pthread_barrier_wait(&barrier);
}