C# 在另一个线程(Unity3D)中从数据库检索数据
我目前有一个从数据库检索数据并在unity3D中可视化的代码。但是,每次在FixedUpdate()函数中检索数据时,它都会每隔1秒急剧增加一次。我正在考虑使用线程来实现这一点,但我不确定我做错了什么 这是我在线程中调用的函数C# 在另一个线程(Unity3D)中从数据库检索数据,c#,multithreading,unity3d,C#,Multithreading,Unity3d,我目前有一个从数据库检索数据并在unity3D中可视化的代码。但是,每次在FixedUpdate()函数中检索数据时,它都会每隔1秒急剧增加一次。我正在考虑使用线程来实现这一点,但我不确定我做错了什么 这是我在线程中调用的函数 public void retrievefromDB(){ if (timeStep - prevTimeStep > 99) { ti
public void retrievefromDB(){
if (timeStep - prevTimeStep > 99) {
timeStep -= 1; //special for this dataset
query = "SELECT * FROM GridData2 WHERE timestep=" + timeStep;
if (showParent)
query += " AND (Level != 10)";
else
query += " AND (Level == 10)";
query += " AND temperature >= " + minTemp + " AND temperature <= " + maxTemp;
dt.Rows.Clear ();
dt = sqlDB.ExecuteQuery (query);
prevTimeStep = timeStep;
}
}
在把它放进一个线程后,它在一段时间后不断地破坏场景。
谁能告诉我我做错了什么?我该怎么解决呢?无论你做什么,你都需要停止每帧访问数据库 您只需要每隔60帧或更多帧生成一次结果。您可以通过使用一个变量轻松地完成此操作,在该变量中,您可以将自上次调用以来经过的时间相加 对于Unity中的多线程,您有三种选择:
- 用于统一的多线程框架,如
- C#内置线程
您需要小心不要从生成的辅助线程调用特定于Unity的API。发送Vector3、Color等数据结构是可以的,但不要调用GameObjects或Components等参考对象。
- 统一合作计划
协程是Unity模拟多线程的方式。它是一个非常强大的工具,可以让事情在同一线程中异步运行
最初问题的原因相对明显:数据库访问速度慢。如果在
FixedUpdate
方法中内联调用数据库,则在数据库访问发生时,您将暂停游戏的移动(例如,如果必须初始化连接,这可能需要一秒钟)
发布的线程代码的主要问题是每次调用FixedUpdate
时都会启动一个新线程。这意味着你将每秒启动60个新线程(默认情况下),这将很快削弱你的游戏
虽然在这种工作中可以统一使用C#threads,但更好的方法是创建单个线程并允许其管理计时,而不是在每次作业运行时创建一个新线程。这意味着在Awake()
或Start()
中创建线程,然后使用thread.Sleep
或类似方法来处理计时
协同程序(正如Mihai在回答中所建议的那样)对于确定事件的时间非常有用,但它们仍然在游戏线程上运行:如果您将DB代码放在协同程序中,则在运行时仍然会看到暂停。如果必须每秒运行此DB访问,则需要将其放在适当的线程中
也就是说,您是否认为数据库访问可能是不必要的?一个更高性能的模型可能是预先缓存所有数据,并在需要时从内存中使用这些数据。(如果数据是非常动态的,或者如果您在内存受限的环境(如移动设备)中运行,这可能是不可能的…现在终于可以工作了。只需在retrievefromDB()中添加这些 我正在使用来自的threadhelper 所以你可以去看看。
感谢所有帮助过我的人!:) 哦,还有一个问题。如果我想让函数保持每秒更新,我需要更改什么?你可以每秒调用它<代码>任务。工厂使用一个线程池,因此它不像看上去那样昂贵。然而,出于这个目的,协同程序更适合。你还需要停止每帧调用这个。您只需要每隔60帧或更多帧生成一次结果。您可以通过使用一个变量轻松地完成此操作,在该变量中,您可以将自上次调用以来经过的时间相加。通常,如果没有某种同步,您不能访问共享资源。即使假设
sqlDB
是线程安全的(不一定是这样),dt.Rows.Clear()
和dt=…
也绝对不是线程安全的。这只是一场即将发生的灾难。如果你想坚持使用这种代码(这不是一个好主意),你至少需要锁定对dt
的所有访问。当然,在您的代码原样中,这将再次消除并行性,但只需确保只更改lock
中的dt
——在获取锁之前加载数据。同样的情况也适用于timeStep
等。“在将其放入线程后,它会在一段时间后继续破坏场景”-将为每个FixedUpdate()
创建一个新线程,从而导致崩溃。Luaan你能给我一个“锁定”代码的示例吗?我不知道你在说什么,但这似乎很重要,如果我在Start函数中调用线程,它不会更新,只会运行一次。有没有办法不停地重复使用线程而不是创建一个新的线程?在线程的方法中加入一个循环,这样它就可以无限期地运行(具有所需的延迟)。您可能还需要一个标志,可以用来通知线程在请求时干净地终止?那么我该如何添加延迟呢?是的,我的意思是-或者更可能的是,while(!\u threadShouldEnd)
,这样您就可以从线程外部控制终止。如果在专用线程中运行,那么使用thread.Sleep
添加延迟是没有问题的。
void FixedUpdate()
{
Thread testthread = new Thread(new ThreadStart(retrievefromDB));
testthread.Start ();
}
using System.Threading.Tasks;
public class Example
{
void StartOnDifferentThread()
{
Task.Factory
.StartNew(() =>
{
FunctionToRun();
})
.ContinueWith(task =>
{
if (task.IsCompleted)
{
// handle result
}
else if (task.IsFaulted)
{
// handle error
}
});
}
void FunctionToRun()
{
// do stuff
}
}
public void retrievefromDB(){
while(true){
if (timeStep - prevTimeStep > 99) {
timeStep -= 1; //special for this dataset
query = "SELECT * FROM GridData2 WHERE timestep=" + timeStep;
if (showParent)
query += " AND (Level != 10)";
else
query += " AND (Level == 10)";
query += " AND temperature >= " + minTemp + " AND temperature <= " + maxTemp;
dt.Rows.Clear ();
dt = sqlDB.ExecuteQuery (query);
prevTimeStep = timeStep;
}
Thread.Sleep(1);
}
}
testThread = UnityThreadHelper.CreateThread (() =>
{
UnityThreadHelper.TaskDistributor.Dispatch (() => retrievefromDB ());
});
testThread.Start ();