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


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

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

    #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
    计算结束,耗时: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
    
    请按任意键继续. . .
    
          第二次:

    单线程计算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
    计算结束,耗时: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
    
    请按任意键继续. . .
    
           第四次:

    单线程计算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个线程来写图像的不同部分。代码如下:

    #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 = "F:\\Data\\Test\\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 = "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编译的结果,运行的结果如下,第一次:

    创建图像开始
    创建图像结束,耗时:2.852000
    单线程处理图像结束,耗时:20.579000
    创建图像开始
    创建图像结束,耗时:3.261000
    多线程处理图像结束,耗时:29.343000
    29.34 s
    
    请按任意键继续. . .
          第二次:

    创建图像开始
    创建图像结束,耗时:2.034000
    单线程处理图像结束,耗时:22.311000
    创建图像开始
    创建图像结束,耗时:2.217000
    多线程处理图像结束,耗时:30.570000
    30.57 s
    
    请按任意键继续. . .
          第三次:

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

           如果你有更好的方式,望告知,谢谢。






  • 相关阅读:
    String.prototype.getParm
    IOS—通过ChildViewController实现view的切换
    objective-c IBOutletCollection介绍
    iOS方法类:CGAffineTransform的使用大概
    cocoaPods下载使用记录
    objective-c 中的关联介绍
    操作系统--文件管理
    操作系统--设备管理
    操作系统--存储管理的任务
    操作系统--并发进程死锁
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6314024.html
Copyright © 2020-2023  润新知