C# 读取大型JSON文件而不挂起Unity
我正在开发一款手机游戏,需要加载一个约17MB的4D 60X40X60X40整数数组。我目前正在读取JSON中的数据,并使用SimpleJSON.cs在Unity中进行反序列化 使用SimpleJSON解析字符串时会出现问题。游戏挂起,加载文件大约需要30秒 我尝试过使用ijob,但它们不允许使用字符串(不可blittable) 主要优先考虑的是悬挂部分。它不允许我在用户等待加载JSON时向他们提供反馈。当然,降低加载时间和任何提示都会非常有用 我的代码:C# 读取大型JSON文件而不挂起Unity,c#,json,unity3d,C#,Json,Unity3d,我正在开发一款手机游戏,需要加载一个约17MB的4D 60X40X60X40整数数组。我目前正在读取JSON中的数据,并使用SimpleJSON.cs在Unity中进行反序列化 使用SimpleJSON解析字符串时会出现问题。游戏挂起,加载文件大约需要30秒 我尝试过使用ijob,但它们不允许使用字符串(不可blittable) 主要优先考虑的是悬挂部分。它不允许我在用户等待加载JSON时向他们提供反馈。当然,降低加载时间和任何提示都会非常有用 我的代码: IEnumerator StartLo
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;
}
编辑:我已经在使用一个没有区别的协同程序。请注意,协同程序本身是非异步的!在
更新
之后,它仍然在Unity主线程中运行IEnumerator
的每次迭代
您更愿意使用任务/线程,例如(假设文本资源加载的第一部分按预期工作)
private int[,,]loadValues=null;
IEnumerator加载文件()
{
//等待游戏加载其他内容的时间
返回新的等待秒(1f);
文本资产文件;
收益返回文件=Resources.Load(transitionPath)作为TextAsset;
载荷滑动器。值=0.3f;
string transitionString=file.ToString();
荷载滑道值=0.5f;
//不知何故,您必须等待回调到主线程
//最简单的方法是线程安全队列
var actions=new ConcurrentQueue();
//现在启动线程并等待结果
var-thread=新线程(()=>加载线程(操作));
thread.Start();
while(loadValues==null)
{
//处理maint线程中的操作
while(actions.Count>0&&actions.TryDequeue(out-var-action)
{
action?.Invoke();
}
收益返回空;
}
Debug.Log(“已完成加载”);
//现在用“loadValues”
}
私有void加载线程(ConcurrentQueue操作)
{
尝试
{
var N=JSON.Parse(transitionString);
actions.Enqueue(()=>{loadingSlider.value=0.7f;});
var输出=新整数[60,40,60,40];
对于(变量x=0;x<60;x++)
{
对于(变量y=0;y<40;y++)
{
对于(var z=0;z<60;z++)
{
对于(var w=0;w<40;w++)
{
//当然,这取决于您的json格式
输出[x,y,z,w]=N[x][y][z][w];
}
}
}
}
actions.Enqueue(()=>{
载荷值=输出;
荷载滑道值=1f;
});
}
捕获(例外e)
{
LogException(e);
Enqueue(()=>{loadValues=newint[0,0,0];});
}
}
注意:在智能手机上输入,但我希望想法变得清晰您可以尝试。我不确定这是否能在四维数组中有效工作,但如果这能提高您的性能,您可以将您的4D数组分离为4片1D数组。此外,您可以使用Json.net,它支持直接从流进行反序列化。您是一个真正的上帝和我都配不上你。太感谢你了!它就像一个魔咒,甚至让加载速度快了近20%。有什么建议可以让加载速度更快吗?@VaggelisStamkopoulos没有我也不^^^好
资源。加载
和文本资产。如果你的文件那么大,ToString
是相当昂贵的。所以如果有poss的话可以通过直接文件在线程中完全异步加载它们,而不是使用它!实际上,如果有其他方法;)例如,将文件放在流化资产中,并使用流式反序列化。。这样,您甚至不必首先将整个内容加载到内存中
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];});
}
}