写代码的时候思考了一会儿memset初始化快还是for循环初始化快。
看了大量的文献资料,结论如下:
- 如果对于一个数组进行赋初值操作,memset肯定比for循环快
- memset赋初值是按字节为单位的,如果要赋一些比较难的值(33,22等),就比较难
- 接上,因为memset是按字节为单位赋初值,当变量所占字节数越大,速度越慢(int的数组比char慢)
测试代码如下:
#include <iostream>
#include <string>
#include <cstring>
#include <chrono>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
using namespace std::chrono;
const int MAXROWNUM = 5e3;
const int MAXCOLNUM = 5e3;
const int loopTimes = 10;
const int loop = 10;
int arr[MAXROWNUM][MAXCOLNUM];
int arr0[MAXROWNUM][MAXCOLNUM];
int arr1[MAXROWNUM][MAXCOLNUM];
int arr2[MAXROWNUM][MAXCOLNUM];
int arr3[MAXROWNUM][MAXCOLNUM];
int arr4[MAXROWNUM][MAXCOLNUM];
int arr5[MAXROWNUM][MAXCOLNUM];
int arr6[MAXROWNUM][MAXCOLNUM];
int arr7[MAXROWNUM][MAXCOLNUM];
int arr8[MAXROWNUM][MAXCOLNUM];
int arr9[MAXROWNUM][MAXCOLNUM];
char str0[MAXROWNUM][MAXCOLNUM];
char str1[MAXROWNUM][MAXCOLNUM];
char str2[MAXROWNUM][MAXCOLNUM];
char str3[MAXROWNUM][MAXCOLNUM];
char str4[MAXROWNUM][MAXCOLNUM];
char str5[MAXROWNUM][MAXCOLNUM];
char str6[MAXROWNUM][MAXCOLNUM];
char str7[MAXROWNUM][MAXCOLNUM];
char str8[MAXROWNUM][MAXCOLNUM];
char str9[MAXROWNUM][MAXCOLNUM];
char str[MAXROWNUM][MAXCOLNUM];
long long memsetfunc_i(){
auto start = system_clock::now();
int len =MAXROWNUM*MAXCOLNUM*sizeof(int);
memset(arr,0, len);
auto end = system_clock::now();
auto tt = duration_cast<microseconds>(end - start);
// printf("memset cost %.3f us\n",tt.count());
return tt.count();
}
long long memsettenfunc_i(){
auto start = system_clock::now();
int len =MAXROWNUM*MAXCOLNUM*sizeof(int);
for (int i = 0; i < loopTimes; ++i) {
memset(arr,0, len);
}
auto end = system_clock::now();
auto tt = duration_cast<microseconds>(end - start);
return tt.count();
}
long long forfunc_i(){
auto start1 = system_clock::now();
for (int i = 0; i < MAXROWNUM; ++i) {
for (int j = 0; j < MAXCOLNUM; ++j) {
arr[i][j] = 0;
}
}
auto end1 = system_clock::now();
auto tt1 = duration_cast<microseconds>(end1 - start1);
return tt1.count();
}
long long fortenfunc_i(){
auto start1 = system_clock::now();
for (int k = 0; k < loopTimes; ++k) {
for (int i = 0; i < MAXROWNUM; ++i) {
for (int j = 0; j < MAXCOLNUM; ++j) {
arr[i][j] = 0;
}
}
}
auto end1 = system_clock::now();
auto tt1 = duration_cast<microseconds>(end1 - start1);
return tt1.count();
}
long long memsetfunc_c(){
auto start = system_clock::now();
int len =MAXROWNUM*MAXCOLNUM*sizeof(char);
memset(str,'0', len);
auto end = system_clock::now();
auto tt = duration_cast<microseconds>(end - start);
// printf("memset cost %.3f us\n",tt.count());
return tt.count();
}
long long memsettenfunc_c(){
auto start = system_clock::now();
int len =MAXROWNUM*MAXCOLNUM*sizeof(char);
for (int i = 0; i < loopTimes; ++i) {
memset(str,'0', len);
}
auto end = system_clock::now();
auto tt = duration_cast<microseconds>(end - start);
return tt.count();
}
long long forfunc_c(){
auto start1 = system_clock::now();
for (int i = 0; i < MAXROWNUM; ++i) {
for (int j = 0; j < MAXCOLNUM; ++j) {
str[i][j] = '0';
}
}
auto end1 = system_clock::now();
auto tt1 = duration_cast<microseconds>(end1 - start1);
return tt1.count();
}
long long fortenfunc_c(){
auto start1 = system_clock::now();
for (int k = 0; k < loopTimes; ++k) {
for (int i = 0; i < MAXROWNUM; ++i) {
for (int j = 0; j < MAXCOLNUM; ++j) {
str[i][j] = '0';
}
}
}
auto end1 = system_clock::now();
auto tt1 = duration_cast<microseconds>(end1 - start1);
return tt1.count();
}
long long memsettendifffunc_c(){
auto start = system_clock::now();
int len =MAXROWNUM*MAXCOLNUM*sizeof(char);
memset(str0,'0', len);
memset(str1,'0', len);
memset(str2,'0', len);
memset(str3,'0', len);
memset(str4,'0', len);
memset(str5,'0', len);
memset(str6,'0', len);
memset(str7,'0', len);
memset(str8,'0', len);
memset(str9,'0', len);
auto end = system_clock::now();
auto tt = duration_cast<microseconds>(end - start);
return tt.count();
}
long long fortendifffunc_c(){
auto start1 = system_clock::now();
for (int i = 0; i < MAXROWNUM; ++i) {
for (int j = 0; j < MAXCOLNUM; ++j) {
str0[i][j] = '0';
str1[i][j] = '0';
str2[i][j] = '0';
str3[i][j] = '0';
str4[i][j] = '0';
str5[i][j] = '0';
str6[i][j] = '0';
str7[i][j] = '0';
str8[i][j] = '0';
str9[i][j] = '0';
}
}
auto end1 = system_clock::now();
auto tt1 = duration_cast<microseconds>(end1 - start1);
return tt1.count();
}
long long memsettendifffunc(){
auto start = system_clock::now();
int len =MAXROWNUM*MAXCOLNUM*sizeof(char);
memset(arr0,0, len);
memset(arr1,0, len);
memset(arr2,0, len);
memset(arr3,0, len);
memset(arr4,0, len);
memset(arr5,0, len);
memset(arr6,0, len);
memset(arr7,0, len);
memset(arr8,0, len);
memset(arr9,0, len);
auto end = system_clock::now();
auto tt = duration_cast<microseconds>(end - start);
return tt.count();
}
long long fortendifffunc(){
auto start1 = system_clock::now();
for (int i = 0; i < MAXROWNUM; ++i) {
for (int j = 0; j < MAXCOLNUM; ++j) {
arr0[i][j] = 0;
arr1[i][j] = 0;
arr2[i][j] = 0;
arr3[i][j] = 0;
arr4[i][j] = 0;
arr5[i][j] = 0;
arr6[i][j] = 0;
arr7[i][j] = 0;
arr8[i][j] = 0;
arr9[i][j] = 0;
}
}
auto end1 = system_clock::now();
auto tt1 = duration_cast<microseconds>(end1 - start1);
return tt1.count();
}
vector<long long> ans;
double getAns(long long(*p)()){
ans.clear();
for (int i = 0; i < loop; ++i) {
ans.push_back((*p)());
}
sort(ans.begin(),ans.end());
double cost = accumulate(ans.begin()+2, ans.end()-2, 0.0) / static_cast<double>(ans.size()-6);
cost = cost/1000;
return cost;
}
int main() {
double m1,m10,f1,f10,cm1,cm10,cf1,cf10,cmd10,cfd10,md10,fd10;
m1 = getAns(memsetfunc_i);
m10 = getAns(memsettenfunc_i);
f1 = getAns(forfunc_i);
f10 = getAns(fortenfunc_i);
cm1 = getAns(memsetfunc_c);
cm10 = getAns(memsettenfunc_c);
cf1 = getAns(forfunc_c);
cf10 = getAns(fortenfunc_c);
cmd10 = getAns(memsettendifffunc_c);
cfd10 = getAns(fortendifffunc_c);
md10 = getAns(memsettendifffunc);
fd10 = getAns(fortendifffunc);
printf("int数组memset一次耗时:%.3fms\tint数组for循环一次耗时:%.3fms\n",m1,f1);
printf("int数组memset十次耗时:%.3fms\tint数组for循环十次耗时:%.3fms\n",m10,f10);
printf("不同的十个int数组memset耗时:%.3fms\t不同的十个int数组for循环耗时:%.3fms\n",md10,fd10);
printf("\n");
printf("char数组memset一次耗时:%.3fms\tchar数组for循环一次耗时:%.3fms\n",cm1,cf1);
printf("char数组memset十次耗时:%.3fms\tchar数组for循环十次耗时:%.3fms\n",cm10,cf10);
printf("不同的十个char数组memset耗时:%.3fms\t不同的十个char数组for循环耗时:%.3fms\n",cmd10,cfd10);
}
数组都开在的栈区,因此数组不能设的太大。。。
运行结果如下:可以佐证上诉的结论。
memset具体的实现可以看一下下面这个博客,写的很仔细:https://www.cnblogs.com/hoodlum1980/p/3505802.html。
以大佬的总结作为我的总结:
- 对数组使用初始化列表,或 memset 两者在底层上可能等效。(msvc编译器将前者处理为后者)。
- 对数组用循环初始化,和使用 memset 初始化相比,很有可能等效。即使不等效(memset 调用了 SSE2 扩展),也不可能达到成为一个优化命题和关注点。
- 如果一定要说有点区别,那就是如果是对一个整数数组用初始化列表或者循环初始化,那么编译器不需要考虑地址对齐的问题(因为编译器必然把数组分配到对齐的地址),而 memset 则需要考虑传入的地址是否已对齐到某个基本粒度,并对此未对齐部分作处理。
- 当对一个随机数据组成的内存块进行清零操作,memset 看起来仿佛是唯一正确的可选方式(如果所在平台无此函数,则可以用手写循环替代)。声明数组时提供初始化列表,声明后再调用 memset 或者使用循环初始化(显然,在能够使用 memset 时,循环写法在高级语言层面不如前者简洁),无论是代码规范还是性能层面,这些写法都不存在值得强调的绝对优劣关系。