2017-11-18 8 views
0

私は、ゲーム内のデータのテキストを読み込んで解析するコードを書いています。例えば、地図には小道具や敵のようなデータが含まれ、そのオブジェクトには呼び出され、読み込まれる独自のファイルがあります。通常はすべてがすぐにロードされます。約1.5秒より遅いマシンでは、5秒以上を取り、それが完了するまでゲームウィンドウが応答しなくなる可能性があります。非同期データの読み取り/解析パフォーマンス

今はロード時間を短くしたままウィンドウをアクティブに保つ方法を検討しています。メインスレッドのバックグラウンドで実行されるタスクにローディングの一部を分けて、ロードが完了するとメインスレッドに状態を切り替えるように指示し、ゲームが続行されます。しかし、私は1.5秒ロード時間から秒のロード時間になりました。このようなバックグラウンドタスクに切り替えると、通常のパフォーマンスですか?私はそれが現在どのように処理されているかの例としていくつかの一般化されたコードを投稿しました。

Map map = null; 
//Main Update Loop 
public void Update() 
{ 
    if(GameState == Active) 
     map.Update(); 
    else 
     ShowLoadingScreen(); 
} 

//LoadWorld gets called from elsewhere, like a UI 
public async void LoadWorld() 
{ 
    GameState = State.Loading; 
    await Task.Run(() => { LoadFile("mapdata", out map); }); 
    GameState = State.Active; 
    map.Start(); 
} 

//This loads the file and reads the first line 
//which tells the reader what sort of object it is 
public void LoadFile(String file, out Map m) 
{ 
    m = new Map(); //create new map 
    StreamReader sr = new StreamReader(file); 
    String line; 
    Object obj = null; 
    while ((line = sr.ReadLine()) != null) 
    { 
     switch(line) 
     { 
     case "A": 
      obj = parseObjectA(line, sr); //continues with its own loop 
      break; 
     case "B": 
      obj = parseObjectB(line, sr); //continues with its own loop 
      break; 
     } 
     map.addObject(obj); 
    } 
} 

//This loops through the reader and fills an object with data, then returns it 
public Object parseObjectA(String line, StreamReader sr) 
{ 
    Object obj = new Object(); 
    while ((line = sr.ReadLine()) != null) 
    { 
     String element; 
     String value; 
     //parseLine is a function that breaks apart the line into an element and value 
     parseLine(line, out element, out value); 
     switch(element) 
     { 
     case "name": 
      obj.Name = value; 
      break; 
     case "position": 
      { 
       int pos = 0; 
       Int32.TryParse(value, out pos); 
       obj.position = pos; 
       break; 
      } 
     } 
    } 
    return obj; 
} 
+0

は、私には見えます。あなたのストリームリーダーの使い方を 'using'ブロックで囲むことも考えてください。私は、パフォーマンスに影響する可能性のあることが他にあるかどうかを確認するために引き続き読んでいます。 – Fabulous

+0

@Fabulous ReadLineはI/O操作であるためスレッドをブロックしません。実際の読み込みを非同期に行う必要がないため、ReadLineAsyncを使用するとパフォーマンスがさらに低下する可能性があります。オーバーヘッド。それは本当ですか? – DangerMcD

+0

戻ったデータの重要な処理を行っている場合、その差はごくわずかです。検討[このスレッド](https://social.msdn.microsoft.com/Forums/vstudio/en-US/a47412ed-1b21-45c2-8554-cc602d6b5ddb/is-streamreaderreadlinelineyncync-much-slower-than-readline?forum=パラレル・エクステンション)。あなたの質問には他の側面もありますが、あなたの質問には対処しています。典型的には、 'async/await'はコールスタックの最下位までカスケードを呼び出します。この場合、 'parseLine'オペレーションでコードを調べることができます。 – Fabulous

答えて

0

私はコメントとしてこれを投稿だろうが、私はまだとても充実した説明にそれを拡大し、許可されていませんよ。

ゲーム開発の観点からは、ローダーをバックグラウンドワーカースレッドとして作成します。これにより、ウィンドウのメインスレッド/フォームはユーザーの入力に応答したままになります。

backgroundWorkerでは個々の作業負荷を必要に応じて個別に行うことができますが、UIは常に応答します。

覚えておくべき重要なことは、必要な変数をクラスのルートに作成してから、バックグラウンドスレッドに挿入することです。そうすることで、すべてがメインスレッドで完了したら結果を簡単に読み取ることができます。一例として、

:あなたは `LoadFile`方法であなたの` StreamReader`から `async`メソッドを使用することができますように

class MainThread 
{ 
    BackgroundLoader bgLoader; 

    public MainThread() 
    { 
     bgLoader = new BackgroundLoader(); 
    } 

    public void LoadItems() 
    { 
     bgLoader.Load(); 
    } 
} 

class BackgroundLoader 
{ 
    BackgroundWorker backgroundWorker = new BackgroundWorker(); 
    // create the variables to hold the results. 
    Map map; 

    public void Load() 
    { 
     backgroundWorker.WorkerReportsProgress = true; 
     backgroundWorker.WorkerSupportsCancellation = true; 
     backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged; 
     backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted; 
     backgroundWorker.DoWork += BackgroundWorker_DoWork; 
     backgroundWorker.RunWorkerAsync(); 
     while (!backgroundWorker.IsBusy) { } 
    } 

    private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // This is where you do the work and load your variables, which you then access once the thread is complete. 
     map = LoadMap(); 
    } 
} 
+0

ありがとう!私はこれが私の問題を解決するのかどうかはわかりませんが、それは確かに調べる価値があります。 – DangerMcD

+0

メインスレッドからタスクを実行しているときにタスクの速度が低下しているので、ロードスタック全体を1つのスレッドとして実行できますが、バックグラウンドスレッドで実行できます。これにより、表示されている問題が削除されることがあります。 – SoulRider

+0

私は見る!明確化のおかげで:) – DangerMcD

関連する問題