是否有实现异步游戏引擎循环的最佳实践?
Posted
技术标签:
【中文标题】是否有实现异步游戏引擎循环的最佳实践?【英文标题】:Are there best practices for implementing an asynchronous game engine loop? 【发布时间】:2011-01-02 03:33:17 【问题描述】:我已经实现了一个游戏引擎循环如下:
public static Boolean Start ( )
if (hasBoard)
// start engine on worker thread
asyncTask = new AsyncResult ( stopEngine, asyncTask );
isRunning = ThreadPool.QueueUserWorkItem ( startEngine, asyncTask );
if (isRunning)
Console.WriteLine ( "[0] Engine started",
DateTime.Now.ToString ( "hh:mm:ss" ) );
else
Console.WriteLine ( "[0] Engine failed to start",
DateTime.Now.ToString ( "hh:mm:ss" ) );
return isRunning;
public static void Stop ( )
Console.WriteLine ( "[0] Engine stopping",
DateTime.Now.ToString ( "hh:mm:ss" ) );
asyncTask.SetAsCompleted ( null, false );
private static void startEngine ( Object task )
while (!( (IAsyncResult)task ).IsCompleted)
Thread.Sleep ( 10000 );
Console.WriteLine ( "[0] Engine running",
DateTime.Now.ToString ( "hh:mm:ss" ) );
private static void stopEngine ( IAsyncResult iaResult )
// clean up resources
Console.WriteLine ( "[0] Engine stopped",
DateTime.Now.ToString ( "hh:mm:ss" ) );
isRunning = false;
我正在使用 Jeff Richter 在他的文章 Implementing the CLR Asynchronous Programming Model 中推荐的 AsyncResult
类。为了能够从 UI 中停止引擎,我使用的实现有点偏离标准异步模式。此实现按预期工作,但是当我偏离标准实践时,我会回到 SO 社区以确保我以正确的方式做事。
此实现是否存在任何人都可以看到的问题?
【问题讨论】:
在游戏引擎循环中,您不会简单地生成一个新线程而不是使用池线程吗? @Mitch:我不太确定。我相信产生一个新线程是标准的。我不知道使用 Threadpool 线程有什么问题。这个游戏引擎是超轻量级的。此外,由于 WinForms UI 在控制中,我认为这是处理游戏循环的好方法。 你为什么在游戏循环中使用 any 线程?如果您需要任何(这确实应该受到很好的质疑),线程应该可能是为特定明确目的预先生成的线程(例如,总是2个线程等. 连续生活)在队列或其他同步中工作。然而,最好的办法就是保持“KISS”。 @pst:可能是因为这是我第一次尝试构建和理解一个非常简单的游戏引擎。 【参考方案1】:由于这听起来像是一个您可以控制的项目,我建议您放弃 APM 并使用 .NET4 中提供的基于 Task
的模型。这是 .NET4 而不是 APM 的推荐方法。 Task
类是 Task Parallel Library (TPL) 的一部分,但它也适用于这些基本的异步作业。
private CancellationTokenSource cts;
public void StartEngine()
if (cts == null)
cts = new CancellationTokenSource();
Task.Factory.StartNew(() => GameLoop(cts.Token), cts.Token);
private void GameLoop(CancellationToken token)
while (true)
token.ThrowIfCancellationRequested();
Thread.Sleep(1000);
Debug.WriteLine("working...");
public void StopEngine()
if (cts != null)
cts.Cancel();
cts = null;
【讨论】:
同意,但我会在创建任务时添加一个 LongRunning 选项。 我进行了修改以添加 LongRunning 选项:Task.Factory.StartNew ( ( ) => startEngine ( cancelSource.Token ), cancelSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default );
【参考方案2】:
我会说,这意味着使用线程池时任务是短暂的,因为其中的线程数量是有限的。
在你的情况下,我会使用 BackgroundWorker,因为你提到了 winforms。 BW 为您处理同步,因此无需使用 InvokeRequired 等即可更新 GUI。
【讨论】:
暗示使用线程池时任务是短暂的 - 根据 Jeff Richter 的说法……除非我真的错过了什么。但是,我确实看到了保持线程池线程任务简短的观点。 @IAbstract:你有这方面的参考吗?读起来会很有趣。 我将不得不再次找到它 - 自从我发表评论以来已经一年半多了。任务寿命短的含义可能是由于默认处理 - 即,如果我们预计执行时间长,我们必须将任务设置为长时间运行。我评论的内容一定是有意义的,但我会尝试找到我所指的内容。 ;)以上是关于是否有实现异步游戏引擎循环的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章
在 Android 中发出异步 HTTP 请求是不是有公认的最佳实践?
使用 fetch 在节点中进行异步 api 调用的最佳实践?
基于Flink+ClickHouse构建实时游戏数据分析最佳实践