質問内容
提示コードですが非同期処理を用いて、アセットを非同期でロードする処理なのですが現状3つの画像がそれぞれ順番にロードされてしまう原因が知りたいです。
提示コードの非同期版のコードでは同じ画像が来た時待機するという処理を行っているのですが、なぜか同期版と同じ秒数処理時間がかかっているため同期処理と同じになって
いると考えられます。
調べたこと
非同期版と同期版両方のプログラムを記述して実行時間を計測
知りたいこと
1,アセットのロードで同じファイルがロードされないようにしながら非同期で行いたい。
2,そもそもどの非同期機能を使ってアセットロードを実装するのが定番なのか知りたいです。
提示コードについて
提示コードはコンポーネント指向を用いています。Componentを継承して非同期で行うアセットロード処理を作り、それをGameObject(コンポーネントをの挙動を管理する)で
処理をまとめて、更に上のSceneで全部のGameObject の非同期処理を一つにまとめ、最後に全部が終わるまで待機してからUpdate()等を実行するという処理内容です。
コンソール
new sprite found sprite new sprite 2000
ソースコード
cpp
1#include <vector> 2#include <future> 3#include <iostream> 4#include <glm/glm.hpp> 5#include <thread> 6#include <mutex> 7#include <condition_variable> 8#include <chrono> 9#include <random> 10#include <thread> 11 12struct Sprite 13{ 14 int handle; 15 std::string path; 16}; 17 18 19std::vector<Sprite> sprites; //ロードした画像リスト 20std::vector<std::string> nowLoad; //現在ロード中の画像リスト 21std::mutex loadMutex; 22std::condition_variable loadCV; 23 24 25/*############################################################## 26# 乱数取得 27##############################################################*/ 28int GetRandom(int rand) 29{ 30 // 現在の時間を取得して種(seed)として使用する 31 auto now = std::chrono::high_resolution_clock::now(); 32 auto seed = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count(); 33 34 // 乱数生成器を初期化 35 std::mt19937_64 generator(seed); 36 37 // ミリ秒単位の乱数を生成 38 std::uniform_int_distribution<int> distribution(0, rand); 39 int random_number = distribution(generator); 40 41 //std::cout << "ミリ秒単位の乱数: " << random_number << std::endl; 42 43 return random_number; 44} 45 46/*############################################################## 47 48# 非同期 版 49 50# スプライトロード関数 51※ テスト用のためロード時間を乱数でミリ秒待機 52##############################################################*/ 53Sprite LoadSprite(const char* filePath) 54{ 55 std::unique_lock<std::mutex> lock(loadMutex); 56 57 // 他のスレッドが同じ画像をロード中であれば待機 58 loadCV.wait(lock, [&filePath]() 59 { 60 for(const std::string& path : nowLoad) 61 { 62 if (path == std::string(filePath)) 63 { 64 return false; 65 } 66 } 67 68 return true; 69 }); 70 71 //スプライトリストから取り出す 72 for (const Sprite& s : sprites) 73 { 74 if (s.path == std::string(filePath)) 75 { 76 std::cout << "found sprite" << std::endl; 77 return s; 78 } 79 } 80 81 std::cout << "new sprite" << std::endl; 82 83 // ロード中の画像リストに追加 84 nowLoad.push_back(std::string(filePath)); 85 lock.unlock(); // ロックを解除して他のスレッドがロードを開始できるようにする 86 87 //画像ロード 88 int milliseconds = 1000; 89 //int milliseconds = GetRandom(1000); 90 std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); 91 92 93 lock.lock(); // ロックを再取得して安全に状態を更新する 94 95 96 //ロードが終わったためリストから削除 97 int i = 0; 98 for(const std::string& s : nowLoad) 99 { 100 if(s == filePath) 101 { 102 break; 103 } 104 105 i++; 106 } 107 nowLoad.erase(nowLoad.begin() + i); 108 109 //ロード済みスプライトリストに追加 110 sprites.push_back(Sprite{ milliseconds, std::string(filePath) }); 111 112 // 画像のロードが完了したことを通知 113 loadCV.notify_all(); 114 115 return sprites.back(); 116 117 118} 119 120/*############################################################## 121 122# 同期 版 123 124# スプライトロード関数 125※ テスト用のためロード時間を乱数でミリ秒待機 126##############################################################*/ 127Sprite Sync_LoadSprite(const char* filePath) 128{ 129 //スプライトリストから取り出す 130 for (const Sprite& s : sprites) 131 { 132 if (s.path == std::string(filePath)) 133 { 134 std::cout << "found sprite" << std::endl; 135 return s; 136 } 137 } 138 139 std::cout << "new sprite" << std::endl; 140 141 //画像ロード 142 int milliseconds =1000; 143 //int milliseconds = GetRandom(1000); 144 std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); 145 146 147 //ロード済みスプライトリストに追加 148 sprites.push_back(Sprite{ milliseconds, std::string(filePath) }); 149 150 return sprites.back(); 151 152 153} 154 155 156 157 158 159/*############################################################## 160# Component 基底 161##############################################################*/ 162class Component 163{ 164public: 165 166 Component() 167 { 168 169 } 170 171 virtual void (*PreLoad())() 172 { 173 return []() -> void 174 { 175 std::cout<<"component"<<std::endl; 176 }; 177 } 178 179}; 180/*############################################################## 181# GameObject 基底 182##############################################################*/ 183class GameObject 184{ 185public: 186 GameObject() 187 { 188 189 } 190 191 std::vector<std::future<void>> getPreLoad() 192 { 193 std::vector<std::future<void>> futures; 194 195 for(Component *c : components) 196 { 197 futures.push_back(std::async(std::launch::async,c->PreLoad())); 198 } 199 200 return futures; 201 } 202 203 void Update() 204 { 205 206 } 207 208 void Render() 209 { 210 211 } 212 213 std::vector<Component*> components; 214}; 215 216/*############################################################## 217# Scene 基底 218##############################################################*/ 219class Scene 220{ 221public: 222 223 std::vector<GameObject*> gameObjects; 224 void Preaload() 225 { 226 std::vector<std::future<void>> futures; 227 for(GameObject *g : gameObjects) 228 { 229 for(std::future<void> &f : g->getPreLoad()) 230 { 231 futures.push_back(std::move(f)); 232 } 233 } 234 235 for(std::future<void> &f : futures) 236 { 237 f.wait(); 238 } 239 } 240 241}; 242 243/*############################################################## 244# Control コンポーネント 245##############################################################*/ 246class Control : public Component 247{ 248public: 249 Control(): Component() 250 { 251 252 } 253 254 void (*PreLoad())() override 255 { 256 return []() ->void 257 { 258 259 260// 同期 261/* 262 auto startTime = std::chrono::high_resolution_clock::now(); 263 264 Sprite sp1 = Sync_LoadSprite("tile1.jpg"); 265 Sprite sp2 = Sync_LoadSprite("tile1.jpg"); 266 Sprite sp3 = Sync_LoadSprite("tile2.jpg"); 267 268 auto endTime = std::chrono::high_resolution_clock::now(); 269 auto time = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime); 270 271 std::cout<<time.count()<<std::endl; 272*/ 273 274//非同期 275 auto startTime = std::chrono::high_resolution_clock::now(); 276 277 Sprite sp1 = LoadSprite("tile1.jpg"); 278 Sprite sp2 = LoadSprite("tile1.jpg"); 279 Sprite sp3 = LoadSprite("tile2.jpg"); 280 281 auto endTime = std::chrono::high_resolution_clock::now(); 282 auto time = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime); 283 284 std::cout<<time.count()<<std::endl; 285 286 287 288 289 290 291 292 }; 293 } 294}; 295 296/*############################################################## 297# Player ゲームオブジェクト 298##############################################################*/ 299class Player : public GameObject 300{ 301public: 302 Player(): GameObject() 303 { 304 components.push_back(new Control()); 305 } 306}; 307 308/*############################################################## 309# Game シーン 310##############################################################*/ 311class Game : public Scene 312{ 313public: 314 Game(): Scene() 315 { 316 gameObjects.push_back(new Player()); 317 } 318}; 319 320 321 322 323int main() 324{ 325 326 Game *g = new Game(); 327 328 g->Preaload(); 329 330 331 332 return 0; 333}
回答1件
あなたの回答
tips
プレビュー