描述
使用基于oneAPI的C++/SYCL实现⼀个高效的并行归并排序。需要考虑数据的分割和合并以及线程之间的协作。
分析&示例
归并排序是⼀种分治算法,其基本原理是将待排序的数组分成两部分,分别对这两部分进行排序,然后将已排 序的子数组合并为⼀个有序数组。可考虑利用了异构并行计算的特点,将排序和合并操作分配给多个线程同时 执行,以提高排序效率。具体实现过程如下:
1. 将待排序的数组分割成多个较小的子数组,并将这些⼦数组分配给不同的线程块进行处理。
2. 每个线程块内部的线程协作完成子数组的局部排序。
3. 通过多次迭代,不断合并相邻的有序⼦数组,直到整个数组有序。
在实际实现中,归并排序可使用共享内存来加速排序过程。具体来说,可以利用共享内存来存储临时数据,减 少对全局内存的访问次数,从而提高排序的效率。另外,在合并操作中,需要考虑同步机制来保证多个线程之 间的数据⼀致性。
需要注意的是,在实际应用中,要考虑到数组大小、线程块大小、数据访问模式等因素,来设计合适的算法和 参数设置,以充分利用目标计算硬件GPU的并行计算能力,提高排序的效率和性能。
作业解答:
#include <iostream>
#include <random>
#include <CL/sycl.hpp>
#include "dpc_common.hpp"
using namespace sycl;
using namespace std;
// 初始化数组函数
void initializeArr(double* arr, int size) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<double> dis(1.0, 100.0);
for (int i = 0; i < size; ++i) {
arr[i] = dis(gen);
}
}
// 使用 SYCL 进行并行归并排序
void ParallelMergeSortBuffer(double data_arr[], int size, queue& q) {
buffer input(data_arr, range(size));
// 使用 SYCL 执行并行归并排序
for (int blockSize = 2; blockSize <= size; blockSize *= 2) {
for (int start = 0; start < size - 1; start += 2 * blockSize) {
int mid = std::min(start + blockSize - 1, size - 1);
int end = std::min(start + 2 * blockSize - 1, size - 1);
q.submit([&](handler& h) {
accessor a(input, h);
// 对每个块执行并行归并
h.parallel_for(range(end - start + 1), [=](id<1> i) {
int leftIndex = start + i;
int rightIndex = mid + 1 + i;
double leftValue = a[leftIndex];
double rightValue = (rightIndex <= end) ? a[rightIndex] : a[end];
// 执行归并操作
if (leftValue > rightValue) {
a[leftIndex] = rightValue;
a[rightIndex] = leftValue;
}
});
});
// 确保在并行操作后正确更新数据
input.set_final_data(data_arr);
}
}
// 等待队列完成
q.wait_and_throw();
}
// 显示数组的函数
void DisplayArray(double a[], int array_size) {
for (int i = 0; i < array_size; ++i) cout << a[i] << " ";
cout << "\n";
}
int main() {
int size = 256;
cout << "\n数组大小: " << size << "\n";
// 在实现选择的默认设备上创建队列
queue q;
cout << "设备: " << q.get_device().get_info<info::device::name>() << "\n";
// 仅为主机访问分配内存
double* data_arr = (double*)malloc(size * sizeof(double));
initializeArr(data_arr, size);
// 使用 ParallelMergeSortBuffer 函数进行并行排序
dpc_common::TimeInterval t_par;
ParallelMergeSortBuffer(data_arr, size, q);
cout << "并行排序时间: " << t_par.Elapsed() << " 秒\n";
// 显示排序后的数组
cout << "排序后的数组(并行): ";
DisplayArray(data_arr, size);
free(data_arr); // 释放内存
return 0;
}
运行截图: