如何在XNA中使用线程来运行数据库查询?

3

我目前正在使用XNA开发一个项目,该项目从本地SQL数据库中提取有关每个对象(每个对象将显示在屏幕上)的信息(ID、名称、文件位置等)。

我希望在单独的线程上运行我的数据库查询,以便在数据库挂起或发生其他意外事件时,渲染屏幕不会冻结。我正在使用XNA 4.0,并且该应用程序仅在Windows上运行。这是否可能,如果可能,如何实现?


1
游戏开始时,难道不应该将这些信息缓存起来吗? - user1228
是的,程序启动时会缓存一些信息。还有其他信息需要在程序运行时由数据库更新,这些新值需要显示在屏幕上。 - NexAddo
3个回答

2

我想要研究一下使用异步调用数据库的方法。一旦我有了一些进展,我会回复你的。谢谢! - NexAddo
结果证明,我们并不需要将数据库调用变成异步的。感谢所有的帮助。 - NexAddo

0

根本不要这样做。认真的。使用线程有很好的理由,但你的理由是虚假的:

如果数据库挂起或发生其他意外事件,渲染屏幕不会冻结

数据库不会挂起,意外事件是无法预测的。例如,当数据库不回答3分钟时,你如何应对?显示一些未知的对象屏幕吗?


1
我认为问题的本质是如何在程序尝试从数据库获取数据时保持屏幕响应,即使它执行正确,对于大型或复杂查询或慢速网络连接可能需要几秒钟。在这种意义上,是的,数据库会“挂起”,而且当程序等待时,如果UI线程在调用上被阻塞,它将无法呈现。 - KeithS
问题在于,以所给的示例来看,这没有任何意义 - 例如,在游戏世界加载内容的同时,您无法在空游戏世界中玩耍。 - TomTom
将来我会更加清晰明了。一个场景可能是,在从数据库加载所有初始游戏对象之后,屏幕上某个对象的一些信息从应用程序外部进行更新。如果由于某种原因它需要花费比预期更长的时间,我不希望UI在此期间挂起。然后,在更新信息后,它将在屏幕上显示新信息。 - NexAddo

0
你所说的“最好”是什么意思?使用线程有很多种方式,它们都有各自的优点和缺点。
显式地声明一个新线程并启动它可以使你对该线程的执行状态具有最直接的控制:
var myDbThread = new Thread(()=>myDbRepo.GetRecordById<MyEntity>(idString));
myDbThread.Start();

现在,只要您有对myDbThread的引用,就可以中止它、暂停它、加入它等等。但是,随着控制权的到来,责任也随之而来;您必须自己管理创建的线程。
对于大多数并行任务,建议使用线程池。然而,您会失去一些控制:
Action myDbLambda = () => myEntityProperty = myDbRepo.GetRecordById<MyEntity>(idString);
var asyncResult = myDbLambda.BeginInvoke();

一旦asyncResult.IsComplete返回true,myEntityProperty就有了值。您还可以将其构建为Func,并使用回调来设置值(这是推荐的)。异步模型内置于BeginInvoke()/EndInvoke()方法对中,许多异常(如超时)都由线程池处理,它会简单地重新启动超时的线程。但是,您不能“放弃”并终止线程池线程,“加入”线程池线程有点棘手,如果您正在启动大量线程,则线程池将以250毫秒间隔开始它们,这可能不是处理器的最佳使用方式。

有许多使用线程池的方法;在委托在.NET编程中变得更加重要之前,在v3.5中,ThreadPool.QueueUserWorkItem是主要方法。现在,正如我所说,委托具有BeginInvoke和EndInvoke方法,允许您使用异步模型在幕后启动后台进程。在WinForms/WPF中,您还可以创建BackgroundWorker组件,它们是事件驱动的,允许您在GUI元素中监视进度和完成情况。

需要注意的一件事是,在ASP.NET中几乎从不使用后台线程是一个好主意。除非您真的知道自己在做什么,否则最好的情况是您无法获得发送到工作线程的行为结果,最坏的情况是您可能会崩溃您的站点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接