多线程与单线程Base16编码时间对比

134 阅读4分钟

说明

实现base16编码,二进制转换为字符串, 原来数据一个字节有8位,经过base16编码后拆分为两个4位字节(最大值16),所以实现base16转码后数据量会扩大一倍,拆分后的字节映射到0123456789abcdef

单线程Base16编码

#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <chrono>

using namespace std;
using namespace chrono;

// base16对应的映射表
static const char base16[] = "0123456789abcdef";

void Base16Encode(const unsigned char* data, int size, unsigned char* out)
{
	for (int i = 0; i < size; i++)
	{
		unsigned char d = data[i];
		char a = base16[d >> 4];  // 通过右移获取高4位
		char b = base16[d & 0x0F]; // 与0x0F进行与操作,获得低4位

		out[i * 2] = a;
		out[i * 2 + 1] = b;

	}
}

int main()
{
	string data = "base16编码测试";
	unsigned char out[1024] = { 0 };

	Base16Encode((unsigned char*)data.c_str(), data.size(), out);

	// 测试单线程base16编码效率
	{
		// 初始化测试数据
		vector<unsigned char> in_data;
		in_data.resize(1024 * 1024 * 10);

		for (int i = 0; i < in_data.size(); i++)
		{
			in_data[i] = i % 256;
		}

		vector<unsigned char> out_data;
		out_data.resize(in_data.size() * 2);  // base16编码,需要扩大两倍

		auto start = system_clock::now();  //记录开始时间

		Base16Encode(in_data.data(), in_data.size(), out_data.data());

		auto end = system_clock::now();  //记录结束时间

		auto duration = duration_cast<milliseconds>(end - start);  // 单位为毫秒

		cout << "单线程执行时间为:" << duration.count() << "毫秒" << endl;

	}


    std::cout << out << "Hello World!\n";
}

单线程执行结果

可以看到单线程执行所消耗的时间为34毫秒

image.png

多线程测试

#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <chrono>

using namespace std;
using namespace chrono;

// base16对应的映射表
static const char base16[] = "0123456789abcdef";

void Base16Encode(const unsigned char* data, int size, unsigned char* out)
{
	for (int i = 0; i < size; i++)
	{
		unsigned char d = data[i];
		char a = base16[d >> 4];  // 通过右移获取高4位
		char b = base16[d & 0x0F]; // 与0x0F进行与操作,获得低4位

		out[i * 2] = a;
		out[i * 2 + 1] = b;

	}
}

void Base16EncodeThread(const vector<unsigned char> &data, vector<unsigned char> &out)
{
	int size = data.size();
	int th_count = thread::hardware_concurrency(); // CPU硬件支持的核心数

	// 切片数据
	int slice_count = size / th_count;  // 余数丢弃了

	// 如果数据量小的话只切一片
	if (size < th_count)
	{
		th_count = 1;
		slice_count = size;
	}

	// 使用vector存放线程
	vector<thread> ths;

	ths.resize(th_count);

	// 任务分配到各个线程

	for (int i = 0; i < th_count; i++)
	{
		int offset = i * slice_count;
		int count = slice_count;

		// 最后一个线程会多处理一些数据
		if (th_count > 1 && i == th_count - 1)
		{
			count = slice_count + size % th_count;
		}

		ths[i] = thread(Base16Encode, data.data() + offset, count, out.data());
	}

	// 等待所有线程处理结束

	for(auto&th : ths)
	{
		th.join();
	}



}


int main()
{
	string data = "base16编码测试";
	unsigned char out[1024] = { 0 };

	Base16Encode((unsigned char*)data.c_str(), data.size(), out);

	// 测试多线程base16编码效率
	{
		// 初始化测试数据
		vector<unsigned char> in_data;
		in_data.resize(1024 * 1024 * 10);

		for (int i = 0; i < in_data.size(); i++)
		{
			in_data[i] = i % 256;
		}

		vector<unsigned char> out_data;
		out_data.resize(in_data.size() * 2);  // base16编码,需要扩大两倍

		auto start = system_clock::now();  //记录开始时间

		Base16EncodeThread(in_data, out_data);

		auto end = system_clock::now();  //记录结束时间

		auto duration = duration_cast<milliseconds>(end - start);  // 单位为毫秒

		cout << "多线程执行时间为:" << duration.count() << "毫秒" << endl;

	}


    std::cout << out << "Hello World!\n";
}

多线程执行结果

可以看到多线程执行时间为11毫秒

image.png

C++17中多线程处理结果

#include <iostream>
#include <vector>
#include <chrono>
#include <execution>  // C++17

using namespace std;
using namespace chrono;

// base16对应的映射表
static const char base16[] = "0123456789abcdef";


int main()
{

	// C++17多线程base16编码效率
	{
		// 初始化测试数据
		vector<unsigned char> in_data;
		in_data.resize(1024 * 1024 * 10);

		for (int i = 0; i < in_data.size(); i++)
		{
			in_data[i] = i % 256;
		}

		vector<unsigned char> out_data;
		out_data.resize(in_data.size() * 2);  // base16编码,需要扩大两倍

		auto start = system_clock::now();  //记录开始时间


		// C++17

		std::for_each(std::execution::par, in_data.begin(), in_data.end(), [&](auto& d)
			{
				char a = base16[d >> 4];  // 通过右移获取高4位
				char b = base16[d & 0x0F]; // 与0x0F进行与操作,获得低4位

				int index = &d - in_data.data();   // 获得数据的位置
				out_data[index * 2] = a;
				out_data[index * 2 + 1] = b;

				
			});


		auto end = system_clock::now();  //记录结束时间

		auto duration = duration_cast<milliseconds>(end - start);  // 单位为毫秒

		cout << "C++17多线程执行时间为:" << duration.count() << "毫秒" << endl;

	}

}


测试结果

C++17方式耗时长的原因可能是lambda表达式,每个字节的处理都要进入一次lambda表达式,因此开销会比较大,也有可能是Debug模式占用时间较多

image.png