【发布时间】:2019-03-01 08:44:18
【问题描述】:
我让自己陷入了这样一种境地,在“正常”的 c# 领域可能相对容易解决,但由于 Unity 的注意事项,它有点复杂。
高层次是我有一组需要运行的任务,其中一些可以并行,其中一些是异步的,其他则不是。对于那些可以并行运行的,当每个任务完成时,我需要触发一个事件(在主线程中),让任何感兴趣的人知道任务已经完成。
为了深入了解细节,这是针对 Unity 中的游戏,但是此特定代码要求它不能触及 Unity API,因为它将位于一个单独的纯 c# 项目中。
从概念上讲,在我的游戏中,我有一个“日间转换”。每天晚上当玩家上床睡觉(或因疲惫而昏倒/被敌人击倒)时,游戏将进入加载屏幕以处理我不想在游戏过程中进行的更长时间的运行操作。诸如运行模拟以更新日常经济,或文件 I/O 以加载第二天要使用的东西之类的事情。
这些镜头可能是线程安全的,也可能不是线程安全的,实际上可能是也可能不是真正的异步调用(例如,文件加载将是)。
我的目标是尽可能少地阻塞主线程(一些阻塞将会发生,这是不可避免的,因为某些任务可能会触及 Unity API,这需要在主线程上发生。那些不是线程安全的)。
因为有些事情会是异步的,所以我将所有事情都视为可等待的。
我的 DayTransitioner 类有一个 IDayTransitionAction 对象列表:
public interface IDayTransitionAction
{
bool IsRepeating { get; }
bool IsThreadSafe { get; }
Task ProcessTransitionAsync();
}
这里确实需要发生两个不同的过程。
首先,线程安全(异步或非异步)的代码需要能够以实际上可以并行运行的方式启动,并且当它们完成时,需要在主线程上触发事件。
protected async Task ProcessThreadSafeTasks()
{
//1st kick off in parallel, probably using one of the Task
//methods such as WhenAll or WhenAny or some other voodoo...
//Not really sure what API calls or structure to use to do it...
//As each comes back an event needs to be fired.
//The event needs to occur on the main thread.
//this.OnIndividualItemProcessed();
}
第二个是非线程安全的东西需要运行并等待(我知道这个组中的同步进程会阻塞主线程,但是当一个真正异步时它不应该)。
第二种情况实际上是最容易解决的,因为 Unity 提供了一个强制在主线程上执行的同步上下文。所以我认为后者可以简单地循环等待。
protected async Task ProcessNonThreadSafeTasks()
{
foreach (var actionItem in this.nonThreadSafeActions)
{
await actionItem.ProcessTransitionAsync();
//Raise the OnIndividualItemProcessed event so eventually
//a loading bar can be filled in as tasks complete, though
//this class doesn't know or care about the loading bar
//specifically. Just that interested parties want to know
//when an individual task is completed
this.OnIndividualItemProcessed();
}
}
第一个令人讨厌的案例让我头疼,因为我不确定如何以一种允许它们并行运行的方式启动它们,同时在每个个体完成时发送一个事件(尤其是考虑到Unity 的同步上下文...我假设我必须以某种方式暂时覆盖它)。我将如何实现这一目标?
提前致谢!
另外,作为参考,将调用上述两个方法...
public async Task ProcessTransitionActions()
{
//Used primarily to lock down the lists while processing is ongoing.
//The Add method will dump anything that's attempting to be stored
//to another list to be sorted and added to the main lists after processing
//is finished.
IsProcessing = true;
await this.ProcessThreadSafeTasks();
await this.ProcessNonThreadSafeTasks();
//Purge any actions that aren't repeating.
this.CleanNonRepeatingActions();
//Add any actions that were stored while processing to the main lists.
this.SortStoredActions();
IsProcessing = false;
//Send out an event to allow interested parties to know processing is
//finished.
this.OnProcessingCompleted();
}
编辑 1*
澄清一下,“线程安全”操作旨在在其他线程(真正并行)上运行(或至少能够运行),而不是简单地在主线程上同时运行。就在它们完成时,我需要在主线程中删除该事件特别需要发出的事件。
【问题讨论】:
标签: c# unity3d parallel-processing async-await