通用编程能力训练 -- 设计心得:分步载入的改造(包含异步IO练习)
2009-10-11 15:05
441 查看
目标:将一个顺序载入的系统变成分步载入的系统。
动机:
也许你会说背景线程 可以达到更好的效果, 但是我想说的是在一些情况下是无法使用多线程的。
比如装载Shader程序,这些程序都需要使用CPU进行本地编译。
这时支持分步载入的系统就能根据情况来分散载入任务,平滑资源载入的过程,可以让系统充分利用时间来使前台功能看起来平滑。
另外一个理由是性能,基于多线程的系统总是会为各种锁支付额外的开销,对于Ogre而言,这2种工作模式的性能差异可以达到30%以上。
注意,这个改造方案和多线程工作模式不冲突。
步骤:
1、确保存在 isLoaded() 或类似方法,因为分步载入的结构和异步结构一致.
2、确保存在一个用于记录所有的加载任务的数据成员,如果没有就定义一个.
3、添加一个游标变量记录当前正在处理哪个子对象,可以是一个对象引用、上值、索引、迭代器等.
4、添加一个用于步进载入的函数 bool loadNext(), 在该函数中发起"当前正在处理的子对象"的加载, 并将游标指向下一个对象.
5、添加一个用于直接载入的函数 void loadDirectly(), 该函数使用 基于 while( loadNext()) 的结构来实现自己.
6、在创建母对象的接口上添加一个 bool manualLoad 变量,用于确定是否使用步进加载,或使用原有的直接加载方式.
范例:(注意下面的 + expand / sourceview / plaincopy to clipboard / print / ?)
动机:
也许你会说背景线程 可以达到更好的效果, 但是我想说的是在一些情况下是无法使用多线程的。
比如装载Shader程序,这些程序都需要使用CPU进行本地编译。
这时支持分步载入的系统就能根据情况来分散载入任务,平滑资源载入的过程,可以让系统充分利用时间来使前台功能看起来平滑。
另外一个理由是性能,基于多线程的系统总是会为各种锁支付额外的开销,对于Ogre而言,这2种工作模式的性能差异可以达到30%以上。
注意,这个改造方案和多线程工作模式不冲突。
步骤:
1、确保存在 isLoaded() 或类似方法,因为分步载入的结构和异步结构一致.
2、确保存在一个用于记录所有的加载任务的数据成员,如果没有就定义一个.
3、添加一个游标变量记录当前正在处理哪个子对象,可以是一个对象引用、上值、索引、迭代器等.
4、添加一个用于步进载入的函数 bool loadNext(), 在该函数中发起"当前正在处理的子对象"的加载, 并将游标指向下一个对象.
5、添加一个用于直接载入的函数 void loadDirectly(), 该函数使用 基于 while( loadNext()) 的结构来实现自己.
6、在创建母对象的接口上添加一个 bool manualLoad 变量,用于确定是否使用步进加载,或使用原有的直接加载方式.
范例:(注意下面的 + expand / sourceview / plaincopy to clipboard / print / ?)
// MultiThreadTest_Console2.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "windows.h" #include <string> #include <vector> #include <algorithm> // 模拟资源加载 // time: 186min; unsigned int gFrameIndex; // 子对象 class SubObject { public: SubObject(const std::string& name, unsigned int size) :mName(name) ,mSize(size) { } std::string mName; unsigned int mSize; }; // 子对象加载器 class SubObjectManager/* : public Singleton<SubObjectManager>*/ { public: typedef std::vector<SubObject*> SubObjects; public: SubObjectManager(){} ~SubObjectManager(){} public: SubObject* load(const std::string& name) { unsigned int size = rand()%100; std::string _name = name; Sleep(size); SubObject* so = new SubObject(_name, size); mSubObjects.push_back(so); return so; } SubObject* getSubObject(const std::string& name) { for( SubObjects::iterator it = mSubObjects.begin(); it != mSubObjects.end(); ++it) { if((*it)->mName == name) return *it; } return NULL; } private: SubObjects mSubObjects; }; struct Task; class AnSyncResourceLoaderListener { public: virtual void processCompleted(const Task* task){}; }; struct Task { typedef std::vector<AnSyncResourceLoaderListener*> Lisnters; unsigned int mID; std::string mName; Lisnters mLisnters; void megry( const Task& other) { if( !isSameTask(other)) return; for( Lisnters::const_iterator other_it = other.mLisnters.begin(); other_it != other.mLisnters.end(); ++other_it) { Lisnters::iterator this_it = std::find(mLisnters.begin(), mLisnters.end(), *other_it); if( this_it == mLisnters.end()) { mLisnters.push_back(*other_it); } } } bool isSameTask( const Task& other) { return other.mName == mName; } void notifyCompleted() { for( Lisnters::iterator it = mLisnters.begin(); it != mLisnters.end(); ++it) { (*it)->processCompleted(this); } } bool operator ==(const Task& other) { return mID == other.mID && mName == other.mName; } }; class AnSyncResourceLoader/* : public Singleton<AnSyncResourceLoader>*/ { public: typedef std::vector<Task> TaskQuene; public: AnSyncResourceLoader(SubObjectManager* pSubObjectManager) :mNextTaskID(0) ,mSubObjectManager(pSubObjectManager) { InitializeCriticalSection (&mRawTaskQueneCS); InitializeCriticalSection (&mCompletedTaskQueneCS); } ~AnSyncResourceLoader() { DeleteCriticalSection (&mRawTaskQueneCS); DeleteCriticalSection (&mCompletedTaskQueneCS); } public: void pushRawTask( Task& task) { EnterCriticalSection (&mRawTaskQueneCS) ; // 策略 // 1、已经加载了--》直接添加到完成队列 // 2、已经提交该任务了(不管是否正在处理)--》合并 Listener // 3、不存在--》直接添加 // 情况1 TaskQuene::iterator raw_it = std::find(mRawTaskQuene.begin(),mRawTaskQuene.end(),task); if( raw_it != mRawTaskQuene.end()) { raw_it->megry(task); } // 情况2 else { TaskQuene::iterator completed_it = std::find(mCompletedTaskQuene.begin(),mCompletedTaskQuene.end(),task); if( completed_it != mCompletedTaskQuene.end()) { completed_it->megry(task); } // 情况3 else { task.mID = mNextTaskID++; mRawTaskQuene.push_back(task); } } LeaveCriticalSection (&mRawTaskQueneCS) ; } Task popRawTask(const Task& task) { EnterCriticalSection (&mRawTaskQueneCS) ; Task out; TaskQuene::iterator raw_it = std::find(mRawTaskQuene.begin(),mRawTaskQuene.end(),task); if( raw_it != mRawTaskQuene.end()) { out = *raw_it; mRawTaskQuene.erase(raw_it); } return out; LeaveCriticalSection (&mRawTaskQueneCS) ; } void pushCompletedTask( const Task& task) { EnterCriticalSection (&mCompletedTaskQueneCS); // 策略 // 1、已经存在,还没通知主线程将回调发送出去--》合并Listener // 2、不存在--》直接添加 // 情况1 TaskQuene::iterator completed_it = std::find(mCompletedTaskQuene.begin(),mCompletedTaskQuene.end(),task); if( completed_it != mCompletedTaskQuene.end()) { completed_it->megry(task); } // 情况2 else { mCompletedTaskQuene.push_back(task); } LeaveCriticalSection (&mCompletedTaskQueneCS); } Task popCompletedTask(const Task& task) { Task out; EnterCriticalSection (&mCompletedTaskQueneCS) ; TaskQuene::iterator completed_it = std::find(mCompletedTaskQuene.begin(),mCompletedTaskQuene.end(),task); if( completed_it != mCompletedTaskQuene.end()) { out = *completed_it; mCompletedTaskQuene.erase(completed_it); } LeaveCriticalSection (&mCompletedTaskQueneCS) ; return out; } public: // 多线程函数 DWORD WINAPI doLoad( LPVOID lpThreadParameters) { while(true) { if( mRawTaskQuene.empty()) continue; Task task = mRawTaskQuene.front(); mSubObjectManager->load(task.mName); popRawTask(task); pushCompletedTask(task); } return 0; } // 主线程函数 public: void notifyCompleted() { EnterCriticalSection (&mCompletedTaskQueneCS); for( TaskQuene::iterator it = mCompletedTaskQuene.begin(); it != mCompletedTaskQuene.end(); ++it) { it->notifyCompleted(); } mCompletedTaskQuene.clear(); LeaveCriticalSection (&mCompletedTaskQueneCS); } private: CRITICAL_SECTION mRawTaskQueneCS; CRITICAL_SECTION mCompletedTaskQueneCS; TaskQuene mRawTaskQuene; TaskQuene mCompletedTaskQuene; unsigned int mNextTaskID; SubObjectManager* mSubObjectManager; }; class BaseObject : public AnSyncResourceLoaderListener { public: typedef std::vector<std::string> RawResourceList; typedef std::vector<SubObject*> SubObjects; public: BaseObject(const RawResourceList& resources,AnSyncResourceLoader* pLoader) :mNextLoadIndex(0) ,mCompletedCount(0) ,mLoaded(false) ,mAllRawResourceLoading(false) ,mLoader(pLoader) { mResources = resources; } ~BaseObject(){} public: virtual void processCompleted(const Task* task) { printf("加载完成[%s],frame[%u]/n", task->mName.c_str(), gFrameIndex); if(++mCompletedCount == mResources.size()) mLoaded = true; }; public: bool loadNext() { if( mAllRawResourceLoading) return false; std::string taskName = mResources[mNextLoadIndex]; Task task; task.mLisnters.push_back(this); task.mName = taskName; mLoader->pushRawTask(task); printf("发起加载[%s],frame[%u]/n", taskName.c_str(), gFrameIndex); mNextLoadIndex++; if( mNextLoadIndex >= mResources.size()) mAllRawResourceLoading = true; return true; } bool isLoaded() { return mLoaded; } private: RawResourceList mResources; SubObjects mSubObjects; bool mLoaded; bool mAllRawResourceLoading; unsigned int mNextLoadIndex; unsigned int mCompletedCount; AnSyncResourceLoader* mLoader; }; DWORD WINAPI doLoad( LPVOID lpThreadParameters) { AnSyncResourceLoader* pAnSyncResourceLoader = (AnSyncResourceLoader*)(lpThreadParameters); return pAnSyncResourceLoader->doLoad(lpThreadParameters); } int _tmain(int argc, _TCHAR* argv[]) { SubObjectManager subObjectManager; AnSyncResourceLoader anSyncResourceLoader(&subObjectManager); HANDLE hThread = CreateThread( NULL, 0, doLoad, &anSyncResourceLoader, 0, NULL); BaseObject::RawResourceList r; r.push_back("dasdasda"); r.push_back("21212"); r.push_back("xxxxxsda"); r.push_back("5555555sda"); BaseObject* bo = new BaseObject(r,&anSyncResourceLoader); gFrameIndex = 0; while(true) { gFrameIndex++; // 更新 anSyncResourceLoader.notifyCompleted(); if(!bo->isLoaded()) bo->loadNext(); else break; } getchar(); return 0; }
相关文章推荐
- 通用编程能力训练:发布-订阅模式
- 通用编程能力训练:template
- 通用编程能力训练:Memory Track(2012-01-29 19:02)
- Silverlight游戏设计(Game Design):(十四)练习用游戏素材资源的获取及相关工具使用心得 --转
- 编程设计:cosos2d-x之C++与Java混编通用接口
- 编程基本功训练:流程图画法及练习
- LeetCode编程练习 - Search Insert Position学习心得
- LeetCode编程练习 - Maximum Subarray学习心得
- LeetCode编程练习 - Contains Duplicate Ⅱ学习心得
- LeetCode编程练习 - Remove Duplicates from Sorted List学习心得
- LeetCode编程练习 - Reverse Integer学习心得
- Silverlight游戏设计(Game Design):(十四)练习用游戏素材资源的获取及相关工具使用心得
- 【编程题目】设计包含 min 函数的栈
- 编程能力提高-----循环的设计技巧(for、while)
- LeetCode编程练习 - Add Digits学习心得
- LeetCode编程练习 - Roman to Integer学习心得
- 编程基本功训练:流程图画法及练习
- LeetCode编程练习 - Remove Duplicates from Sorted Array学习心得
- LeetCode编程练习 - Best Time to Buy and Sell Stock学习心得
- LeetCode编程练习 - Valid Anagram学习心得