背景:
对于13GB大小的文件,逐行读取,后写到一个新文件。单个线程,进行耗时242s。这里的处理操作比较简单,仅仅是直接写到一个新的文件。如果处理操作耗时越长,多线程的优点越能够显现出来。
采用多线程:
初步的时候采用的方案,是读取数据后,直接写到一个新的文件中。5个线程耗时9s,单个线程耗时4s。
多线程的读写操作,读写之前都要加锁:
while(true)
{
{
CAutoLock lock(m_lock);
//cout<<"start read data:"<<endl;
int count=0;
//int totalcount=0;
if(!getline(m_InStream, oneline))
{
break;
}
mycount++;
//outfile << oneline<< endl;
}
//
//usleep(10);
// EnterCriticalSection( &g_CS );
// cout<<num<<":"<<mycount<<endl;
// LeaveCriticalSection( &g_CS );
{
CAutoLock lock(m_lock);
//sleep(10);
outfile << oneline<< endl;//写操作
}
}
从上述结果可以发现多线程的反而不如单线的速度。经过分析是因为写操作选择不合理,该操作,要进行等待,将时间耗费在排队上面,成为多线程的瓶颈,等待锁耗时长。所以,改成sleep操作,用该操作进行多线程效率的测试。此外需要注意的是如果sleep的时间过短,小于读操作或者等待锁的时间的话,则此时的多线程反而比单线程低效。因为瓶颈在于等待锁的获取。可以尝试下sleep(0.01)和sleep(10)。注意各个sleep的单位是秒还是毫秒。usleep呢?
测试过程读取的是10Wt条数据,测试结果显示,单线程,大概68s,而5个线程大概15s。提速效果明显。
通过类的方式进行代码如下:
//出现输出顺序紊乱的原因:
//往控制台窗口输出的过程(cout)并不是多线程安全的,在一个线程输出过程中另一个线程也可以输出。
//解决办法:
//对输出出进行同步,利用临界区就可以很容易办到。
//代码修改如下:
//CRITICAL_SECTION g_CS; //定义一个临界区
//InitializeCriticalSection( &g_CS ); //在程序开始的地方,对临界区初始化。具体见下面的程序。
//在所有涉及到输出的地方改为:
//EnterCriticalSection( &g_CS );
//cout<<"first thread cout:"<<i<<endl;
//LeaveCriticalSection( &g_CS );
<pre name="code" class="cpp">
int mycount;//计数,统计读取的行数
CRITICAL_SECTION g_CS; //定义一个临界区,cout的时候,使得整齐化,不会出现顺序紊乱的情形。
class MyGroup
{
public:
MyGroup()
{
m_Initialized = false;
};
~MyGroup() {};
public:
void StartReadDynamic(int num);
static void * CallBackDynamic(void *, int);
static MyGroup * CurMy;
void CommitToService(const char * filename);
private:
bool m_Initialized;
boost::mutex m_IoMutex;
CCriticalSection m_lock;
ifstream m_InStream;
};
<pre name="code" class="cpp">MyGroup* MyGroup::CurMy = NULL;
void * MyGroup::CallBackDynamic(void *args, int num)
{
CurMy->StartReadDynamic(num);
return NULL;
}
void MyGroup::StartReadDynamic(int num)
// void StartReadFile()
{
// int my_num= *((int*)(&num));//线程编号
cout<<"thread "<<num<<" runing"<<endl;
time_t start,stop;
start=time(NULL);
string filename = "/data1/kgops/data/AudioFileSub.txt";//save the fulldata
ifstream infile(filename.c_str());
string oneline;
uint32_t linecount = 0;
while(true)
{
{
//CAutoLock lock(m_lock);//读的时候,加锁
//cout<<"start read data:"<<endl;
int count=0;
//int totalcount=0;
if(!getline(m_InStream, oneline))
{
break;
}
mycount++;
//outfile << oneline<< endl;
}
//
usleep(10);//模拟实际的操作的时长
// EnterCriticalSection( &g_CS );//输出整齐化
// cout<<num<<":"<<mycount<<endl;//使得输出整齐化,
// LeaveCriticalSection( &g_CS );//使得输出有序
// {
// CAutoLock lock(m_lock);
// sleep(0.001);
// }
}
}
void MyGroup::CommitToService(const char * filename)
{
time_t t1,t2;
t1=time(NULL);
mycount=0;
m_InStream.open(filename);
StartReadDynamic(1);//单进程方案
// boost::thread_group MyThreadGroup;//多线程方案(5个进程)
// CurMy = this;
// for (int i = 0; i < 5; i++)
// {
// MyThreadGroup.create_thread(boost::bind(&MyGroup::CallBackDynamic, this, i));
// }
// MyThreadGroup.join_all();
m_InStream.close();
t2=time(NULL);
cout<<"Cost:"<<t2-t1<<".num:"<<mycount<<endl;
}
int main()
{
MyGroup g1;
InitializeCriticalSection( &g_CS );
g1.CommitToService("/data1/kgops/data/AudioFileSub.txt");
}
最后,对于5000W条的数据进行处理,5个线程耗时271s。单个线程,耗时1055s。加速效果显著。
参考:
http://blog.youkuaiyun.com/qiurisuixiang/article/details/6645634