多线程写图像文件的一点小测试(Boost + Gual)
2012-06-29 13:45
405 查看
转载自: /article/1360984.html
在处理遥感图像中,发现往往比较耗时的是在数据的IO中,尤其是在O(写入)的时候更加耗时。GDAL可以支持图像的多线程写入,下面结合实例进行简单的测试,看看实际效果会不会提高。
在这里我使用的是boost库的thread库来进行多线程创建。下面先使用计算PI来对boost的thread有个简单的说明。这里的计时使用的是boost的progress_timer。下面是使用多线程计算PI的一段小代码,对于多线程计算的10部分没有加起来。
注: 以下boost为开源库,请自己去下载。
通过对上面的代码进行测试,使用的是Release编译的结果,结果大概如下,第一次:
第三次:
通过四次测试,发现多线程还是能够稍微提高点速度,但是不知道为什么,单线程计算的时候,时间跳跃比较大,起伏较大,不知道是什么原因,有知道的童鞋望不吝告知。
下面是创建了一个10000×10000的单波段图像,格式是Erdas的img格式,图像的内容是按照行号对255取余的结果,结果图像就是一条一条的黑白相间的波纹。多线程还是使用10个线程来写图像的不同部分。代码如下:
注: 以下gdal为开源库,请自己去下载。
(可参考:
GDAL源码剖析(一)
GDAL源码剖析(二)之编译说明
)
依旧使用Release编译的结果,运行的结果如下,
第一次:
第三次:
创建图像开始
创建图像结束,耗时:2.007000
单线程处理图像结束,耗时:20.285000
创建图像开始
创建图像结束,耗时:2.267000
多线程处理图像结束,耗时:28.723000
28.73 s
请按任意键继续. . .
就贴三次吧,在我电脑上测试了不下十次,发现都是多线程写入的速度慢,但是结果图像是对的。对于出现这种情况,也是出乎意料的,按理说多线程应该更快才对,但是这里却出现了相反的情况,不知道是不是boost库多线程的问题还是多线程写入图像的问题,不管是什么情况,对于想使用多线程来创建图像的人来说,这条路可能比想象中的要更加艰难。
如果你有更好的方式,望告知,谢谢。
以下补充网友对上述现象的解释:
(1) 读写最好还是不要多线程,硬盘读写的速度有限,单线程时已经满负荷了,多线程又会增加线程之间的切换,会增加时间。
如果想增加读写速度,应该增加硬盘,做raid
(2)首先是硬盘的写入是串行的,CPU的计算才是并行的,如果你偏重计算那么多线程能提高,要不怎么叫做并行计算呢;
如果侧重存储,除非数据量达到足以体现优势的程度,否则加上线程之间切换的损耗当然会效率更加地下。
(3)这个是按照算法来说的,目前来说大多数的算法都是很快的,瓶颈都在磁盘的IO上,我们针对大多数的算法都进行过测试,基本一半以上的时间都耗费在磁盘的IO上。
比如我处理一个影像,处理数据用了1分钟,写入图像用了2分钟,那你把你的算法优化的很牛逼,10秒中搞定,你的效率提高了多少,但是如果我多线程写入的话,
我效率提高一倍,也就是写入图像用了1分钟,那这个效率明显比你优化你的算法来的实惠。这个东西还是要针对算法来说的。
(4)磁盘IO单线程顺序写时最快的,如果多线程写,磁盘的磁头要不断重新寻址,所以写入速度反而会慢。
在处理遥感图像中,发现往往比较耗时的是在数据的IO中,尤其是在O(写入)的时候更加耗时。GDAL可以支持图像的多线程写入,下面结合实例进行简单的测试,看看实际效果会不会提高。
在这里我使用的是boost库的thread库来进行多线程创建。下面先使用计算PI来对boost的thread有个简单的说明。这里的计时使用的是boost的progress_timer。下面是使用多线程计算PI的一段小代码,对于多线程计算的10部分没有加起来。
注: 以下boost为开源库,请自己去下载。
#include <stdio.h> #include <boost/progress.hpp> //boost计时函数 #include <boost/thread.hpp> //boost多线程 #include <boost/bind.hpp> //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; i<10; i++) { boost::thread thrd(boost::bind(&ThreadPi, i*iSize1, (i+1)*iSize1)); thrd.join(); } } int main() { //不使用多线程处理 progress_timer *pTime = new progress_timer(); // 开始计时 printf("单线程计算PI\n"); double dsPi = CalcPi_S(); printf("计算结束,耗时:%f PI=%18.16lf\n", pTime->elapsed(), dsPi); //使用多线程处理 pTime->restart(); // 开始计时 printf("多线程计算PI\n"); CalcPi_M(); printf("计算结束,耗时:%f\n", pTime->elapsed()); delete pTime; system("pause"); return 0; }
通过对上面的代码进行测试,使用的是Release编译的结果,结果大概如下,第一次:
第二次: 单线程计算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 请按任意键继续. . .
第三次:
第四次: 单线程计算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个线程来写图像的不同部分。代码如下:
注: 以下gdal为开源库,请自己去下载。
(可参考:
GDAL源码剖析(一)
GDAL源码剖析(二)之编译说明
)
// 下面是创建了一个10000×10000的单波段图像, // 格式是Erdas的img格式,图像的内容是按照行号对255取余的结果, // 结果图像就是一条一条的黑白相间的波纹。多线程还是使用10个线程来写图像的不同部分 #include <stdio.h> #include "gdal_priv.h" #include <boost/progress.hpp> //boost计时函数 #include <boost/thread.hpp> #include <boost/bind.hpp> 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; i<iHeight; i++) { int iValue = i % 255; memset(pBuf, iValue, sizeof(DT_8U)*iWidth); //超出AOI外 pBand->RasterIO(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; i<iEnd; i++) { int iValue = i % 255; memset(pBuf, iValue, sizeof(DT_8U)*iWidth); //超出AOI外 pBand->RasterIO(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; i<10; i++) { boost::thread thrd(boost::bind(&ThreadFun, pszFile, i*1000, (i+1)*1000/*, i*/)); thrd.join(); } return true; } int main() { //不使用多线程处理 progress_timer *pTime = new progress_timer(); // 开始计时 const char* pszFileSingle = "Single.img"; printf("创建图像开始\n"); CreateImage(pszFileSingle); printf("创建图像结束,耗时:%f\n", pTime->elapsed()); pTime->restart(); // 开始计时 SingleProcess(pszFileSingle); printf("单线程处理图像结束,耗时:%f\n", pTime->elapsed()); //使用多线程处理 pTime->restart(); // 开始计时 const char* pszFileMulti = "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编译的结果,运行的结果如下,
第一次:
第二次: 创建图像开始 创建图像结束,耗时:2.034000 单线程处理图像结束,耗时:22.311000 创建图像开始 创建图像结束,耗时:2.217000 多线程处理图像结束,耗时:30.570000 30.57 s 请按任意键继续. . .
第三次:
创建图像开始
创建图像结束,耗时:2.007000
单线程处理图像结束,耗时:20.285000
创建图像开始
创建图像结束,耗时:2.267000
多线程处理图像结束,耗时:28.723000
28.73 s
请按任意键继续. . .
就贴三次吧,在我电脑上测试了不下十次,发现都是多线程写入的速度慢,但是结果图像是对的。对于出现这种情况,也是出乎意料的,按理说多线程应该更快才对,但是这里却出现了相反的情况,不知道是不是boost库多线程的问题还是多线程写入图像的问题,不管是什么情况,对于想使用多线程来创建图像的人来说,这条路可能比想象中的要更加艰难。
如果你有更好的方式,望告知,谢谢。
以下补充网友对上述现象的解释:
(1) 读写最好还是不要多线程,硬盘读写的速度有限,单线程时已经满负荷了,多线程又会增加线程之间的切换,会增加时间。
如果想增加读写速度,应该增加硬盘,做raid
(2)首先是硬盘的写入是串行的,CPU的计算才是并行的,如果你偏重计算那么多线程能提高,要不怎么叫做并行计算呢;
如果侧重存储,除非数据量达到足以体现优势的程度,否则加上线程之间切换的损耗当然会效率更加地下。
(3)这个是按照算法来说的,目前来说大多数的算法都是很快的,瓶颈都在磁盘的IO上,我们针对大多数的算法都进行过测试,基本一半以上的时间都耗费在磁盘的IO上。
比如我处理一个影像,处理数据用了1分钟,写入图像用了2分钟,那你把你的算法优化的很牛逼,10秒中搞定,你的效率提高了多少,但是如果我多线程写入的话,
我效率提高一倍,也就是写入图像用了1分钟,那这个效率明显比你优化你的算法来的实惠。这个东西还是要针对算法来说的。
(4)磁盘IO单线程顺序写时最快的,如果多线程写,磁盘的磁头要不断重新寻址,所以写入速度反而会慢。
相关文章推荐
- 多线程写图像文件的一点小测试
- 多线程写图像文件的一点小测试
- 用PC-Lint测试Boost的程序时需要在.LNT文件中附加的定义
- FRG图像文件格式(三):性能测试
- 【lucene系列学习四】log4j日志文件实现多线程的测试
- 多线程程序操作共享区域(文件)的一点体会
- OpenCV数字图像处理十:读写txt文件,在图像训练和测试的时候经常用到
- Java多线程生成测试文件
- 多线程程序操作共享区域(文件)的一点体会
- java多线程测试页面,log4j打印信息到指定文件中
- 参考多线程读写文件(转,未测试)
- 多线程锁的一点测试
- 关于多线程Thread 与 Runnable 的一点总结
- 使用Boost.Asio写的多线程TCP转发代理服务器
- C++Builder 多线程文件发送系统
- 常见的图像文件格式 无损压缩
- 解决多线程同时读写一个文件的问题
- 根据当前文件夹下所有文件随机自动生成训练和测试样本列表
- 借助WebService实现多线程上传文件
- PHP文件缓存效率测试