-
Notifications
You must be signed in to change notification settings - Fork 175
ファイル読み込み高速化(行データ読み出しのマルチスレッド対応) #2021
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,6 +33,8 @@ | |
#include "util/window.h" | ||
#include "CSelectLang.h" | ||
#include "String_define.h" | ||
#include <atomic> | ||
#include <future> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 指摘ではないですが、標準c++のヘッダーファイルは たぶん趣味の領域なのでどちらでもいいです。 |
||
|
||
/*! | ||
ファイルを読み込んで格納する(分割読み込みテスト版) | ||
|
@@ -84,7 +86,7 @@ EConvertResult CReadManager::ReadFile_To_CDocLineMgr( | |
EConvertResult eRet = RESULT_COMPLETE; | ||
|
||
try{ | ||
CFileLoad cfl(type->m_encoding); | ||
CFileLoad cfl( type->m_encoding ); | ||
|
||
bool bBigFile; | ||
#ifdef _WIN64 | ||
|
@@ -104,33 +106,64 @@ EConvertResult CReadManager::ReadFile_To_CDocLineMgr( | |
pFileInfo->SetFileTime( FileTime ); | ||
} | ||
|
||
// ReadLineはファイルから 文字コード変換された1行を読み出します | ||
// エラー時はthrow CError_FileRead を投げます | ||
CEol cEol; | ||
CNativeW cUnicodeBuffer; | ||
EConvertResult eRead; | ||
constexpr DWORD timeInterval = 33; | ||
ULONGLONG nextTime = GetTickCount64() + timeInterval; | ||
while( RESULT_FAILURE != (eRead = cfl.ReadLine( &cUnicodeBuffer, &cEol )) ){ | ||
if(eRead==RESULT_LOSESOME){ | ||
eRet = RESULT_LOSESOME; | ||
// 行データ読み込みに使うスレッド数 (メインスレッドを含む) | ||
const int nThreadCount = (std::max)(1, (int)std::thread::hardware_concurrency()); | ||
|
||
std::vector<CFileLoad> vecThreadFileLoads( nThreadCount ); | ||
std::vector<CDocLineMgr> vecThreadDocLineMgrs( nThreadCount ); | ||
std::vector<std::future<EConvertResult>> vecWorkerFutures; | ||
std::atomic<bool> bCanceled = false; | ||
|
||
size_t nOffsetBegin = cfl.GetNextLineOffset( (size_t)cfl.GetFileSize() ); | ||
for( int i = nThreadCount - 1; 0 <= i; i-- ){ | ||
// 分担する範囲を決める | ||
const size_t nOffsetEnd = nOffsetBegin; | ||
nOffsetBegin = cfl.GetNextLineOffset( (size_t)((double)cfl.GetFileSize() / nThreadCount * i) ); | ||
|
||
if( nOffsetBegin == nOffsetEnd ){ | ||
continue; | ||
} | ||
const wchar_t* pLine = cUnicodeBuffer.GetStringPtr(); | ||
int nLineLen = cUnicodeBuffer.GetStringLength(); | ||
CDocEditAgent(pcDocLineMgr).AddLineStrX( pLine, nLineLen ); | ||
//経過通知 | ||
ULONGLONG currTime = GetTickCount64(); | ||
if(currTime >= nextTime){ | ||
nextTime += timeInterval; | ||
NotifyProgress(cfl.GetPercent()); | ||
// 処理中のユーザー操作を可能にする | ||
if( !::BlockingHook( NULL ) ){ | ||
throw CAppExitException(); //中断検出 | ||
} | ||
|
||
vecThreadFileLoads[i].Prepare( cfl, nOffsetBegin, nOffsetEnd ); | ||
vecThreadDocLineMgrs[i].SetMemoryResource(pcDocLineMgr->GetMemoryResource()); | ||
|
||
if( i == 0 ){ | ||
// 最後はメインスレッドで処理 | ||
eRet = ReadLines( true, vecThreadFileLoads[i], vecThreadDocLineMgrs[i], bCanceled ); | ||
}else{ | ||
// ワーカースレッドで処理 | ||
vecWorkerFutures.push_back( | ||
std::async( | ||
std::launch::async, | ||
&CReadManager::ReadLines, | ||
this, | ||
false, | ||
std::ref(vecThreadFileLoads[i]), | ||
std::ref(vecThreadDocLineMgrs[i]), | ||
std::ref(bCanceled) | ||
) | ||
); | ||
} | ||
} | ||
|
||
// ファイルをクローズする | ||
// ワーカースレッド待ち合わせ | ||
for( auto&& future : vecWorkerFutures ){ | ||
EConvertResult eRetSub = future.get(); | ||
if( eRetSub != RESULT_COMPLETE ){ | ||
eRet = eRetSub; | ||
} | ||
} | ||
|
||
if( bCanceled.load() ){ | ||
// 中断 | ||
throw CAppExitException(); | ||
} | ||
|
||
// 各スレッドの処理結果をpcDocLineMgrに集約 | ||
for( int i = 0; i < nThreadCount; i++ ){ | ||
pcDocLineMgr->AppendAsMove( vecThreadDocLineMgrs[i] ); | ||
} | ||
|
||
cfl.FileClose(); | ||
} | ||
catch(const CAppExitException&){ | ||
|
@@ -192,3 +225,58 @@ EConvertResult CReadManager::ReadFile_To_CDocLineMgr( | |
// CModifyVisitor().ResetAllModifyFlag(pcDocLineMgr, 0); | ||
return eRet; | ||
} | ||
|
||
/*! | ||
ファイルから行データを読み込む | ||
@param[in] bMainThread メインスレッドで実行しているかどうか | ||
@param[in] cFileLoad ファイル読み込みクラス | ||
@param[out] cDocLineMgr 読み込んだ行データを格納 | ||
@param[in,out] bCanceled 処理中断フラグ | ||
@returns 読み込み処理結果 | ||
*/ | ||
EConvertResult CReadManager::ReadLines( | ||
bool bMainThread, | ||
CFileLoad& cFileLoad, | ||
CDocLineMgr& cDocLineMgr, | ||
std::atomic<bool>& bCanceled | ||
) | ||
{ | ||
CEol cEol; | ||
CNativeW cUnicodeBuffer; | ||
EConvertResult eRead; | ||
constexpr DWORD timeInterval = 33; | ||
auto nextTime = GetTickCount64() + timeInterval; | ||
EConvertResult eRet = RESULT_COMPLETE; | ||
|
||
while( RESULT_FAILURE != (eRead = cFileLoad.ReadLine( &cUnicodeBuffer, &cEol )) ){ | ||
if( eRead == RESULT_LOSESOME ){ | ||
eRet = RESULT_LOSESOME; | ||
} | ||
|
||
if( bCanceled.load() ){ | ||
break; | ||
} | ||
|
||
const wchar_t* pLine = cUnicodeBuffer.GetStringPtr(); | ||
const auto nLineLen = cUnicodeBuffer.GetStringLength(); | ||
CDocEditAgent(&cDocLineMgr).AddLineStrX( pLine, nLineLen ); | ||
|
||
if( bMainThread ){ | ||
// 経過通知 | ||
const auto currTime = GetTickCount64(); | ||
if( currTime >= nextTime ){ | ||
nextTime += timeInterval; | ||
NotifyProgress( cFileLoad.GetPercent() ); | ||
// 処理中のユーザー操作を可能にする | ||
if( !::BlockingHook( NULL ) ){ | ||
// 中断検知 | ||
bCanceled.store( true ); | ||
eRet = RESULT_FAILURE; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
|
||
return eRet; | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -134,6 +134,30 @@ void CDocLineMgr::DeleteLine( CDocLine* pcDocLineDel ) | |||||
} | ||||||
} | ||||||
|
||||||
//! 他のCDocLineMgrの内容を末尾に追加する | ||||||
//! 元のCDocLineMgrの内容は空になる | ||||||
void CDocLineMgr::AppendAsMove( CDocLineMgr& other ) | ||||||
{ | ||||||
if( other.GetDocLineTop() == nullptr ){ return; } | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 指摘じゃないです。ほほ趣味ですが、こう書いても同じ意味。
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GetDocLineTop() がもしbool型なら There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. どっちでもいいみたいです。 誤って代入するのを防止する目的で、 if ( nullptr == xxx() ){ |
||||||
|
||||||
// 双方向リンクをつなぐ | ||||||
other.GetDocLineTop()->m_pPrev = m_pDocLineBot; | ||||||
if( m_pDocLineBot != nullptr ){ | ||||||
m_pDocLineBot->m_pNext = other.GetDocLineTop(); | ||||||
} | ||||||
|
||||||
// 先頭/末尾を更新 | ||||||
if( m_pDocLineTop == nullptr ){ | ||||||
m_pDocLineTop = other.GetDocLineTop(); | ||||||
} | ||||||
m_pDocLineBot = other.GetDocLineBottom(); | ||||||
|
||||||
m_nLines += other.GetLineCount(); | ||||||
|
||||||
// 所有権が移ったので空っぽにしておく | ||||||
other._Init(); | ||||||
} | ||||||
|
||||||
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- // | ||||||
// 行データへのアクセス // | ||||||
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- // | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
指摘ではないですが、
util/string_ex.h
に似たような定義がたくさんあるので、そちらで集中管理してもいいんじゃないかと思いました。