背景:

对于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。加速效果显著。