Fat*_*tie 4 .net c# multithreading unity-game-engine
在Unity中,说您有一个GameObject。因此,可能是劳拉·克罗夫特(Lara Croft),马里奥(Mario),愤怒的鸟,特定的立方体,特定的树或其他任何东西。
(回想一下,Unity不是OO,它是ECS。Component可以“附加”到s的s本身可以GameObject用OO语言创建,也可以不使用OO语言创建,但是Unity本身只是GameObjects 的列表和运行任何Components 的框架引擎。因此,实际上Unity当然是“完全”的单线程,甚至没有一种概念上的方法可以在另外1个线程上执行与“实际Unity”(“游戏对象列表”)相关的任何操作。)
所以说在多维数据集上,我们有一个Component称为Test
public class Test: MonoBehaviour {
Run Code Online (Sandbox Code Playgroud)
它确实具有Update伪函数,因此Unity知道我们要在每个帧中运行一些东西。
private void Update() { // this is Test's Update call
Debug.Log(ManagedThreadId); // definitely 101
if (something) DoSomethingThisParticularFrame();
}
Run Code Online (Sandbox Code Playgroud)
假设统一线程为“ 101”。
这样更新(实际上是任何游戏对象上任何框架的任何更新)都将打印101。
因此,由于某种原因,我们有时会选择每隔几秒钟运行一次DoSomethingThisFrame。
因此,每一帧(显然,在“该” Unity线程上……有/只能有一个线程),Unity在各种游戏对象上运行所有Update调用。
因此,在一个特定的帧(比如说游戏的第819秒的第24帧)上,它确实DoSomethingThisParticularFrame为我们运行。
void DoSomethingThisParticularFrame() {
Debug.Log(ManagedThreadId); // 101 I think
TrickyBusiness();
}
Run Code Online (Sandbox Code Playgroud)
我认为这也会打印101。
async void TrickyBusiness() {
Debug.Log("A.. " + ManagedThreadId); // 101 I think
var aTask = Task.Run(()=>BigCalculation());
Debug.Log("B.. " + ManagedThreadId); // 101 I think
await aTask;
Debug.Log("C.. " + ManagedThreadId); // In Unity a mystery??
ExplodeTank();
}
void BigCalculation() {
Debug.Log("X.. " + ManagedThreadId); // say, 999
for (i = 1 to a billion) add
}
Run Code Online (Sandbox Code Playgroud)
好吧
我很确定在A上它将打印101。我认为。
我想在B它将打印101
我相信,但是我不确定,在X它将启动另一个BigCalculation线程。(说999。)(但谁知道那可能是错误的。)
我们在C处使用什么线程,它(试图?)在哪里炸破坦克????
(例如,考虑这个很好的答案,并注意第一个示例输出“ Thread After Await:12”。12与29不同。)
但这在Unity中毫无意义-
...怎么可能TrickyBusiness在“另一个线程”上-整个场景是重复的,还是什么意思?
还是这种情况(尤其是在Unity中并且仅在IDK中),
在TrickyBusiness开始的时候,Unity实际上将那个(什么-类“ Test”的裸实例??)放在另一个线程上?
await内容时,它在C或A上打印什么?似乎:
1 显然,一些辅助计算(例如,渲染等)是在其他内核上完成的,但是实际的“基于框架的游戏引擎”是一个纯线程。(无论如何,都不可能“访问”主机框架线程:例如,在编程时,例如本机插件或在另一个线程上运行的某种计算,您所能做的就是在组件上保留组件的标记和值在运行每个框架时要查看和使用的引擎框架线程。)
异步作为高级抽象与线程无关。
由await 所控制后,在哪个线程上恢复执行System.Threading.SynchronizationContext.Current。
例如,WindowsFormsSynchronizationContext将确保从GUI线程开始的执行将在结束后在GUI线程上继续await执行,因此,如果您在WinForms应用程序中执行测试,ManagedThreadId则在之后将看到相同的结果await。
例如,不关心保留线程,将允许代码在任何线程上恢复。AspNetSynchronizationContext
例如,ASP.NET Core 根本没有同步上下文。
Unity会发生什么,取决于它所具有的功能SynchronizationContext.Current。您可以检查它返回的内容。
上面是事件的“足够真实”表示,也就是说,您可以从正常无聊的日常async / await代码中得到期望,这些代码与常规Task<T>函数有关,这些常规函数以通常的方式返回结果。
您绝对可以调整以下行为:
您可以通过ConfigureAwait(false)等待调用来放弃上下文捕获。由于未捕获上下文,因此上下文附带的所有内容都会丢失,包括在原始线程上恢复的能力(对于与线程有关的上下文)。
您可以设计一个异步代码,即使您不使用异步代码,也可以在线程之间有意识地进行切换ConfigureAwait(false)。一个很好的例子可以在Raymond Chen的博客(第1部分,第2部分)中找到,并展示了如何在使用
await ThreadSwitcher.ResumeBackgroundAsync();
Run Code Online (Sandbox Code Playgroud)
然后回来
await ThreadSwitcher.ResumeForegroundAsync(Dispatcher);
Run Code Online (Sandbox Code Playgroud)因为整个异步/等待机制是松散耦合的(您可以使用await 任何定义GetAwaiter()方法的对象),所以您可以提出一个对象,该对象GetAwaiter()在当前线程/上下文中可以做您想做的所有事情(实际上,这正是上面的项目符号项)是)。
SynchronizationContext.Current不会神奇地在其他人的代码上强制执行其方法:反之亦然。SynchronizationContext.Current之所以生效,是因为Task<T> 选择执行尊重它。您可以自由地实现一个忽略它的等待方式。
| 归档时间: |
|
| 查看次数: |
543 次 |
| 最近记录: |