多线程写图像文件的一点小测试

在处理遥感图像中,发现往往比较耗时的是在数据的IO中,尤其是在O(写入)的时候更加耗时。GDAL可以支持图像的多线程写入,下面结合实例进行简单的测试,看看实际效果会不会提高。

在这里我使用的是boost库的thread库来进行多线程创建。下面先使用计算PI来对boost的thread有个简单的说明。这里的计时使用的是boost的progress_timer。下面是使用多线程计算PI的一段小代码,对于多线程计算的10部分没有加起来。

[cpp] view plaincopyprint?
01.#include
02.#include //boost计时函数
03.#include //boost多线程
04.#include //boost bind库
05.using namespace boost;
06.
07.//计算PI的个数
08.int iSize = 1000000000;
09.int iSize1 = 100000000;
10.
11.//使用普通方式计算
12.double CalcPi_S()
13.{
14. double dPi = 0.0;
15. int iFlag = 1;
16.
17. for (int k=0; k<=iSize; k++)
18. {
19. dPi = dPi + iFlag/(2*k+1.0);
20. iFlag = -iFlag;
21. }
22.
23. return dPi*4;
24.}
25.
26.//多线程计算核心函数
27.void ThreadPi(int iStart, int iEnd)
28.{
29. double dPi = 0.0;
30. int iFlag = 1;
31. for (int k=iStart; k<=iEnd; k++)
32. {
33. dPi = dPi + iFlag/(2*k+1.0);
34. iFlag = -iFlag;
35. }
36.
37. printf("%18.16lf\n", dPi*4);
38.}
39.
40.//多线程计算函数
41.void CalcPi_M()
42.{
43. for (int i=0; ielapsed(), dsPi);
58.
59. //使用多线程处理
60. pTime->restart(); // 开始计时
61. printf("多线程计算PI\n");
62. CalcPi_M();
63. printf("计算结束,耗时:%f\n", pTime->elapsed());
64.
65. delete pTime;
66. system("pause");
67. return 0;
68.}
#include
#include //boost计时函数
#include //boost多线程
#include //boost bind库
using namespace boost;

//计算PI的个数
int iSize = 1000000000;
int iSize1 = 100000000;

//使用普通方式计算
double CalcPi_S()
{
double dPi = 0.0;
int iFlag = 1;

for (int k=0; k<=iSize; k++)
{
dPi = dPi + iFlag/(2*k+1.0);
iFlag = -iFlag;
}

return dPi*4;
}

//多线程计算核心函数
void ThreadPi(int iStart, int iEnd)
{
double dPi = 0.0;
int iFlag = 1;
for (int k=iStart; k<=iEnd; k++)
{
dPi = dPi + iFlag/(2*k+1.0);
iFlag = -iFlag;
}

printf("%18.16lf\n", dPi*4);
}

//多线程计算函数
void CalcPi_M()
{
for (int i=0; ielapsed(), dsPi);

//使用多线程处理
pTime->restart(); // 开始计时
printf("多线程计算PI\n");
CalcPi_M();
printf("计算结束,耗时:%f\n", pTime->elapsed());

delete pTime;
system("pause");
return 0;
} 通过对上面的代码进行测试,使用的是Release编译的结果,结果大概如下,第一次:

[cpp] view plaincopyprint?
01.单线程计算PI
02.计算结束,耗时:9.643000 PI=3.1415926545880506
03.9.64 s
04.
05.多线程计算PI
06.3.1415926635893259
07.0.0000000150000000
08.0.0000000083333333
09.0.0000000058333333
10.0.0000000045000000
11.0.0000000036666667
12.0.0000000030952381
13.0.0000000026785714
14.0.0000000023611111
15.0.0000000021111111
16.计算结束,耗时:8.498000
17.8.50 s
18.
19.请按任意键继续. . .
单线程计算PI
计算结束,耗时:9.643000 PI=3.1415926545880506
9.64 s

多线程计算PI
3.1415926635893259
0.0000000150000000
0.0000000083333333
0.0000000058333333
0.0000000045000000
0.0000000036666667
0.0000000030952381
0.0000000026785714
0.0000000023611111
0.0000000021111111
计算结束,耗时:8.498000
8.50 s

请按任意键继续. . .
第二次:

[cpp] view plaincopyprint?
01.单线程计算PI
02.计算结束,耗时:12.039000 PI=3.1415926545880506
03.多线程计算PI
04.3.1415926635893259
05.0.0000000150000000
06.0.0000000083333333
07.0.0000000058333333
08.0.0000000045000000
09.0.0000000036666667
10.0.0000000030952381
11.0.0000000026785714
12.0.0000000023611111
13.0.0000000021111111
14.计算结束,耗时:8.550000
15.8.55 s
16.
17.请按任意键继续. . .
单线程计算PI
计算结束,耗时:12.039000 PI=3.1415926545880506
多线程计算PI
3.1415926635893259
0.0000000150000000
0.0000000083333333
0.0000000058333333
0.0000000045000000
0.0000000036666667
0.0000000030952381
0.0000000026785714
0.0000000023611111
0.0000000021111111
计算结束,耗时:8.550000
8.55 s

请按任意键继续. . .
第三次:

[cpp] view plaincopyprint?
01.单线程计算PI
02.计算结束,耗时:14.473000 PI=3.1415926545880506
03.多线程计算PI
04.3.1415926635893259
05.0.0000000150000000
06.0.0000000083333333
07.0.0000000058333333
08.0.0000000045000000
09.0.0000000036666667
10.0.0000000030952381
11.0.0000000026785714
12.0.0000000023611111
13.0.0000000021111111
14.计算结束,耗时:8.500000
15.8.50 s
16.
17.请按任意键继续. . .
单线程计算PI
计算结束,耗时:14.473000 PI=3.1415926545880506
多线程计算PI
3.1415926635893259
0.0000000150000000
0.0000000083333333
0.0000000058333333
0.0000000045000000
0.0000000036666667
0.0000000030952381
0.0000000026785714
0.0000000023611111
0.0000000021111111
计算结束,耗时:8.500000
8.50 s

请按任意键继续. . .
第四次:

[cpp] view plaincopyprint?
01.单线程计算PI
02.计算结束,耗时:10.898000 PI=3.1415926545880506
03.多线程计算PI
04.3.1415926635893259
05.0.0000000150000000
06.0.0000000083333333
07.0.0000000058333333
08.0.0000000045000000
09.0.0000000036666667
10.0.0000000030952381
11.0.0000000026785714
12.0.0000000023611111
13.0.0000000021111111
14.计算结束,耗时:8.510000
15.8.51 s
16.
17.请按任意键继续. . .
单线程计算PI
计算结束,耗时:10.898000 PI=3.1415926545880506
多线程计算PI
3.1415926635893259
0.0000000150000000
0.0000000083333333
0.0000000058333333
0.0000000045000000
0.0000000036666667
0.0000000030952381
0.0000000026785714
0.0000000023611111
0.0000000021111111
计算结束,耗时:8.510000
8.51 s

请按任意键继续. . .
通过四次测试,发现多线程还是能够稍微提高点速度,但是不知道为什么,单线程计算的时候,时间跳跃比较大,起伏较大,不知道是什么原因,有知道的童鞋望不吝告知。

下面是创建了一个10000×10000的单波段图像,格式是Erdas的img格式,图像的内容是按照行号对255取余的结果,结果图像就是一条一条的黑白相间的波纹。多线程还是使用10个线程来写图像的不同部分。代码如下:

[cpp] view plaincopyprint?
01.#include
02.#include "gdal_priv.h"
03.
04.#include //boost计时函数
05.#include
06.#include
07.using namespace boost;
08.
09.#pragma comment(lib, "gdal_i.lib")
10.
11.typedef unsigned char DT_8U;
12.
13./**
14.* @brief 创建输出图像
15.*/
16.bool CreateImage(const char* pszFile)
17.{
18. GDALAllRegister();
19. GDALDriverH hDriver = GDALGetDriverByName( "HFA" );
20. if( hDriver == NULL )
21. return false;
22.
23. GDALDatasetH hDstDS = GDALCreate( hDriver, pszFile, 10000, 10000, 1, GDT_Byte, NULL ); //创建输出文件
24. if( hDstDS == NULL )
25. return false;
26.
27. GDALClose(hDstDS);
28. return true;
29.}
30.
31.bool SingleProcess(const char* pszFile)
32.{
33. GDALAllRegister();
34.
35. GDALDataset *poSrcDS = (GDALDataset *) GDALOpen( pszFile, GA_Update );
36. if( poSrcDS == NULL )
37. return false;
38.
39. int iWidth = poSrcDS->GetRasterXSize();
40. int iHeight = poSrcDS->GetRasterYSize();
41.
42. GDALRasterBand *pBand = poSrcDS->GetRasterBand(1);
43.
44. DT_8U *pBuf = new DT_8U[iWidth];
45. memset(pBuf, 0, sizeof(DT_8U)*iWidth); //超出AOI外
46.
47. for (int i=0; iRasterIO(GF_Write , 0, i, iWidth, 1, pBuf, iWidth, 1, GDT_Byte, 0, 0);
52. }
53.
54. GDALClose((GDALDatasetH) poSrcDS);
55. return true;
56.}
57.
58.void ThreadFun(const char* pszFile, int iStart, int iEnd/*, int index*/)
59.{
60. GDALAllRegister();
61. GDALDataset *poSrcDS = (GDALDataset *) GDALOpen( pszFile, GA_Update );
62. if( poSrcDS == NULL )
63. return;
64.
65. int iWidth = poSrcDS->GetRasterXSize();
66. int iHeight = poSrcDS->GetRasterYSize();
67.
68. GDALRasterBand *pBand = poSrcDS->GetRasterBand(1);
69.
70. DT_8U *pBuf = new DT_8U[iWidth];
71. memset(pBuf, 0, sizeof(DT_8U)*iWidth); //超出AOI外
72.
73. for (int i=iStart; iRasterIO(GF_Write , 0, i, iWidth, 1, pBuf, iWidth, 1, GDT_Byte, 0, 0);
78. }
79.
80. GDALClose((GDALDatasetH) poSrcDS);
81. //printf("线程%n结束\n", index);
82.}
83.
84.bool MultiProcess(const char* pszFile)
85.{
86. for (int i=0; ielapsed());
105.
106. pTime->restart(); // 开始计时
107. SingleProcess(pszFileSingle);
108. printf("单线程处理图像结束,耗时:%f\n", pTime->elapsed());
109.
110.
111. //使用多线程处理
112. pTime->restart(); // 开始计时
113. const char* pszFileMulti = "F:\\Data\\Test\\Multi.img";
114. printf("创建图像开始\n");
115. CreateImage(pszFileMulti);
116. printf("创建图像结束,耗时:%f\n", pTime->elapsed());
117.
118. pTime->restart(); // 开始计时
119. MultiProcess(pszFileMulti);
120. printf("多线程处理图像结束,耗时:%f\n", pTime->elapsed());
121.
122. delete pTime;
123.
124. system("pause");
125. return 0;
126.}
#include
#include "gdal_priv.h"

#include //boost计时函数
#include
#include
using namespace boost;

#pragma comment(lib, "gdal_i.lib")

typedef unsigned char DT_8U;

/**
* @brief 创建输出图像
*/
bool CreateImage(const char* pszFile)
{
GDALAllRegister();
GDALDriverH hDriver = GDALGetDriverByName( "HFA" );
if( hDriver == NULL )
return false;

GDALDatasetH hDstDS = GDALCreate( hDriver, pszFile, 10000, 10000, 1, GDT_Byte, NULL ); //创建输出文件
if( hDstDS == NULL )
return false;

GDALClose(hDstDS);
return true;
}

bool SingleProcess(const char* pszFile)
{
GDALAllRegister();

GDALDataset *poSrcDS = (GDALDataset *) GDALOpen( pszFile, GA_Update );
if( poSrcDS == NULL )
return false;

int iWidth = poSrcDS->GetRasterXSize();
int iHeight = poSrcDS->GetRasterYSize();

GDALRasterBand *pBand = poSrcDS->GetRasterBand(1);

DT_8U *pBuf = new DT_8U[iWidth];
memset(pBuf, 0, sizeof(DT_8U)*iWidth); //超出AOI外

for (int i=0; iRasterIO(GF_Write , 0, i, iWidth, 1, pBuf, iWidth, 1, GDT_Byte, 0, 0);
}

GDALClose((GDALDatasetH) poSrcDS);
return true;
}

void ThreadFun(const char* pszFile, int iStart, int iEnd/*, int index*/)
{
GDALAllRegister();
GDALDataset *poSrcDS = (GDALDataset *) GDALOpen( pszFile, GA_Update );
if( poSrcDS == NULL )
return;

int iWidth = poSrcDS->GetRasterXSize();
int iHeight = poSrcDS->GetRasterYSize();

GDALRasterBand *pBand = poSrcDS->GetRasterBand(1);

DT_8U *pBuf = new DT_8U[iWidth];
memset(pBuf, 0, sizeof(DT_8U)*iWidth); //超出AOI外

for (int i=iStart; iRasterIO(GF_Write , 0, i, iWidth, 1, pBuf, iWidth, 1, GDT_Byte, 0, 0);
}

GDALClose((GDALDatasetH) poSrcDS);
//printf("线程%n结束\n", index);
}

bool MultiProcess(const char* pszFile)
{
for (int i=0; ielapsed());

pTime->restart(); // 开始计时
SingleProcess(pszFileSingle);
printf("单线程处理图像结束,耗时:%f\n", pTime->elapsed());

//使用多线程处理
pTime->restart(); // 开始计时
const char* pszFileMulti = "F:\\Data\\Test\\Multi.img";
printf("创建图像开始\n");
CreateImage(pszFileMulti);
printf("创建图像结束,耗时:%f\n", pTime->elapsed());

pTime->restart(); // 开始计时
MultiProcess(pszFileMulti);
printf("多线程处理图像结束,耗时:%f\n", pTime->elapsed());

delete pTime;

system("pause");
return 0;
}

依旧使用Release编译的结果,运行的结果如下,第一次:

[cpp] view plaincopyprint?
01.创建图像开始
02.创建图像结束,耗时:2.852000
03.单线程处理图像结束,耗时:20.579000
04.创建图像开始
05.创建图像结束,耗时:3.261000
06.多线程处理图像结束,耗时:29.343000
07.29.34 s
08.
09.请按任意键继续. . .
创建图像开始
创建图像结束,耗时:2.852000
单线程处理图像结束,耗时:20.579000
创建图像开始
创建图像结束,耗时:3.261000
多线程处理图像结束,耗时:29.343000
29.34 s

请按任意键继续. . . 第二次:

[cpp] view plaincopyprint?
01.创建图像开始
02.创建图像结束,耗时:2.034000
03.单线程处理图像结束,耗时:22.311000
04.创建图像开始
05.创建图像结束,耗时:2.217000
06.多线程处理图像结束,耗时:30.570000
07.30.57 s
08.
09.请按任意键继续. . .
创建图像开始
创建图像结束,耗时:2.034000
单线程处理图像结束,耗时:22.311000
创建图像开始
创建图像结束,耗时:2.217000
多线程处理图像结束,耗时:30.570000
30.57 s

请按任意键继续. . . 第三次:

[cpp] view plaincopyprint?
01.创建图像开始
02.创建图像结束,耗时:2.007000
03.单线程处理图像结束,耗时:20.285000
04.创建图像开始
05.创建图像结束,耗时:2.267000
06.多线程处理图像结束,耗时:28.723000
07.28.73 s
08.
09.请按任意键继续. . .
创建图像开始
创建图像结束,耗时:2.007000
单线程处理图像结束,耗时:20.285000
创建图像开始
创建图像结束,耗时:2.267000
多线程处理图像结束,耗时:28.723000
28.73 s

请按任意键继续. . .
就贴三次吧,在我电脑上测试了不下十次,发现都是多线程写入的速度慢,但是结果图像是对的。对于出现这种情况,也是出乎意料的,按理说多线程应该更快才对,但是这里却出现了相反的情况,不知道是不是boost库多线程的问题还是多线程写入图像的问题,不管是什么情况,对于想使用多线程来创建图像的人来说,这条路可能比想象中的要更加艰难。

如果你有更好的方式,望告知,谢谢。
如需更全面地了解编译器优化,请参阅优化注意事项