读取大型 JSON 文件而不挂在 Unity 中
Posted
技术标签:
【中文标题】读取大型 JSON 文件而不挂在 Unity 中【英文标题】:Reading large JSON file without hanging in Unity 【发布时间】:2021-05-29 03:12:47 【问题描述】:我正在开发一个手机游戏,我需要加载一个大约 17MB 的 4D 60X40X60X40 整数数组。我目前正在读取 JSON 中的数据并使用 SimpleJSON.cs 在 Unity 中反序列化。
使用 SimpleJSON 解析字符串时会出现问题。游戏挂起,加载文件大约需要 30 秒。
我尝试过使用 IJobs,但它们不允许使用字符串(非 blittable)。
主要优先的是悬挂部分。它不允许我在用户等待 JSON 加载时向他们提供反馈。当然,减少加载时间和任何有关它的提示都会非常有帮助。
我的代码:
IEnumerator StartLoadFiles()
// Wait to give time for the game to load everything else
yield return new WaitForSeconds(1f);
/// First read the transition matrices. We are using TextAsset
/// because of compatibility issues with android.
TextAsset file;
yield return file = Resources.Load(transitionPath) as TextAsset;
loadingSlider.value = 0.3f;
string transitionString = file.ToString();
loadingSlider.value = 0.5f;
/// We are using SimpleJSON.cs as of now. Maybe there is
/// something faster out there... (Here is where it hangs)
JSONNode N;
yield return N = JSON.Parse(transitionString);
loadingSlider.value = 0.7f;
编辑:我已经在使用协程,没有任何区别。
【问题讨论】:
你可以试试Array Pooling。我不确定这是否会在 4 维数组中有效地工作,但是,如果这对您的情况有任何性能提升,您可以将 4D 数组分离为 4 件 1D 数组。 另外,你可以使用Json.net,它支持直接从流中反序列化。 Deserializing from stream 【参考方案1】:请注意,协程本身不是异步的!它仍然在 Update
之后的 Unity 主线程中运行 IEnumerator
的每次迭代。
您宁愿使用任务/线程,例如(假设文本资产加载的第一部分按预期工作)
private int[,,,] loadValues = null;
IEnumerator StartLoadFiles()
// Wait to give time for the game to load everything else
yield return new WaitForSeconds(1f);
TextAsset file;
yield return file = Resources.Load(transitionPath) as TextAsset;
loadingSlider.value = 0.3f;
string transitionString = file.ToString();
loadingSlider.value = 0.5f;
// Somehow you have to wait for callbacks into the main thread
// simplest way is a thread-safe Queue
var actions = new ConcurrentQueue<Action>();
// Now start the thread and wait for results
var thread = new Thread(() => LoadingThread(actions));
thread.Start();
while(loadValues == null)
// process the actions in the maint hread
while(actions.Count > 0 && actions.TryDequeue(out var action)
action?.Invoke();
yield return null;
Debug.Log("Finished loading");
// Now o something with "loadValues"
private void LoadingThread(ConcurrentQueue actions)
try
var N = JSON.Parse(transitionString);
actions.Enqueue(() => loadingSlider.value = 0.7f;);
var output = new int[60,40,60,40];
for(var x = 0; x < 60; x++)
for(var y = 0; y < 40; y++)
for(var z = 0; z < 60; z++)
for(var w = 0; w < 40; w++)
// Depending on your json format of course
output[x,y,z,w] = N[x][y][z][w];
actions.Enqueue(() =>
loadValues = output;
loadingSlider.value = 1f;
);
catch(Exception e)
Debug.LogException(e);
actions.Enqueue(() => loadValues = new int[0,0,0,0];);
注意:在智能手机上输入,但我希望思路清晰
【讨论】:
你是真正的上帝,我配不上你。太感谢了!它就像一个魅力,甚至使加载速度快了近 20%。关于如何使加载更快的任何提示? @VaggelisStamkopoulos 不,我不是 ^^ 如果您的文件那么大,Resources.Load
和 TextAsset.ToString
也相当昂贵。因此,如果有可能通过直接 FileIO 在线程中完全异步加载它们,请改用它!实际上don't use Resources
如果有任何其他方式;)例如将您的文件放在StreamingAssets
中并使用流式反序列化.. 这样您甚至不必先将整个内容加载到内存中以上是关于读取大型 JSON 文件而不挂在 Unity 中的主要内容,如果未能解决你的问题,请参考以下文章