特别是在 Unity 中,“where"是指等待从字面上返回吗? [英] In Unity specifically, "where" does an await literally return to?

查看:37
本文介绍了特别是在 Unity 中,“where"是指等待从字面上返回吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Unity 中,假设您有一个 GameObject .因此,它可以是劳拉·克罗夫特、马里奥、愤怒的小鸟、特定的立方体、特定的树或其他任何东西.

In Unity, say you have a GameObject . So, it could be Lara Croft, Mario, an angered bird, a particular cube, a particular tree, or whatever.

(回想一下,Unity 不是面向对象的,它是 ECS.您可以附加"到 GameObjectComponent 本身可能会或可能不会在OO 语言,但 Unity 本身只是一个 GameObject 列表和一个帧引擎,每帧在它们上运行任何 Component.因此确实 Unity 当然是完全的"; 单线程,甚至没有一种概念性的方法可以在另一个1 线程上执行与实际 Unity"(游戏对象列表")相关的任何事情.)

(Recall that Unity is not OO, it's ECS. The Components themselves which you can "attach" to a GameObject may or may not be created in an OO language, but Unity itself is just a list of GameObjects and a frame engine that runs any Components on them each frame. Thus indeed Unity is of course "utterly" single-thread, there's not even a conceptual way to do anything relating to "actual Unity" (the "list of game objects") on another1 thread.)

所以说在立方体上我们有一个名为 Test

So say on the cube we have a Component called Test

public class Test: MonoBehaviour {

它确实有一个更新伪函数,所以 Unity 知道我们想要在每一帧运行一些东西.

It does have an Update pseudofunction, so Unity knows we want to run something each frame.

  private void Update() { // this is Test's Update call
     
     Debug.Log(ManagedThreadId); // definitely 101
     if (something) DoSomethingThisParticularFrame();
  }

假设统一线程是101".

Let's say the unity thread is "101".

这样更新(以及任何游戏对象上任何帧的任何更新)将打印 101.

So that Update (and indeed any Update of any frame on any game object) will print 101.

所以有时,也许出于某种原因每隔几秒,我们选择运行 DoSomethingThisFrame.

So from time to time, perhaps every few seconds for some reason, we choose to run DoSomethingThisFrame.

因此,每一帧(显然,在该"Unity 线程上......有/只能有一个线程)Unity 会在各种游戏对象上运行所有更新调用.

Thus, every frame (obviously, on "the" Unity thread ... there is / can only be one thread) Unity runs all the Update calls on the various game objects.

所以在一个特定的帧上(假设是游戏第 819 秒的第 24 帧),假设它确实为我们运行了 DoSomethingThisParticularFrame .

So on one particular frame (let's say the 24th frame of the 819th second of game play) let's say it does run DoSomethingThisParticularFrame for us.

void DoSomethingThisParticularFrame() {

   Debug.Log(ManagedThreadId); // 101 I think
   TrickyBusiness();
}

我假设它也会打印 101.

I assume that will also print 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
}

好的

  1. 我很确定它会在 A 打印 101.我想.

  1. I'm pretty sure at A it will print 101. I think.

我猜在 B 会打印 101

I guess that at B it will print 101

我相信,但我不确定,在 X 它将启动另一个用于 BigCalculation 的线程.(比如说,999.)(但也许这是错误的,谁知道呢.)

I believe, but I'm uncertain, at X it will have started another thread for BigCalculation. (Say, 999.) (But maybe that's wrong, who knows.)

我的问题是,在 Unity 中,C"会发生什么??

我们在 C 的哪个线程上,它(试图?)爆炸坦克????

My question, what happens, in Unity, at "C" ?

What thread are we on at C, where it (tries to?) explode a tank????

(例如,考虑这个 优秀答案,并注意第一个示例输出Thread After Await: 12".12 与 29 不同.)

(For example, consider this excellent answer and notice the first example output "Thread After Await: 12". 12 is different from 29.)

但这在 Unity 中毫无意义 -

But that's meaningless in Unity -

... TrickyBusiness 怎么会在另一个线程"上?- 整个场景被复制是什么意思,或者?

... how can TrickyBusiness be on "another thread" - what would that mean, that the whole scene is duplicated, or?

或者是这种情况(尤其是在 Unity 中且仅在 Unity 中?IDK),

Or is it the case that (in Unity especially and only? IDK),

TrickyBusiness 开始时,Unity 实际上将它(什么 - 类Test"的裸实例??)放在另一个线程上?

at the point where TrickyBusiness begins, Unity actually puts that (what - a naked instance of the class "Test" ??) on another thread?

看起来:

1 很明显,一些辅助计算(例如,渲染等)是在其他内核上完成的,但实际的基于帧的游戏引擎"是在其他内核上完成的.是一根纯线.(以任何方式访问"主引擎框架线程都是不可能的:例如,当您在编程本机插件或在另一个线程上运行的某些计算时,您所能做的就是为组件留下标记和值引擎框架线程在运行每个框架时查看和使用.)

推荐答案

异步作为高级抽象不关心线程.

await 后继续执行的线程 System.Threading.SynchronizationContext.Current控制.

On which thread the execution resumes after an await is controlled by System.Threading.SynchronizationContext.Current.

例如WindowsFormsSynchronizationContext 将确保在 GUI 线程上开始的执行将在 await 之后在 GUI 线程上恢复,因此如果您在 WinForms 应用程序中执行测试,您将看到ManagedThreadIdawait 之后是相同的.

E.g. WindowsFormsSynchronizationContext will make sure the execution that started on the GUI thread will resume on the GUI thread after an await, so if you perform a test in a WinForms application, you will see that ManagedThreadId is the same after an await.

例如AspNetSynchronizationContext 关心保留线程并允许代码在任何线程上恢复.

E.g. AspNetSynchronizationContext does not care about preserving threads and will allow the code to resume on any thread.

例如ASP.NET Core 根本没有同步上下文.

E.g. ASP.NET Core does not have a synchronization context at all.

Unity 中会发生什么取决于它的SynchronizationContext.Current.您可以检查它返回的内容.

Whatever will happen in Unity depends on what it has as its SynchronizationContext.Current. You can examine what it returns.

以上是事件的足够真实"表示,也就是说,您可以从与常规 Task<T> 返回结果的函数相关的普通无聊的日常异步/等待代码中得到什么以通常的方式.

The above is a "true enough" representation of events, that is, what you can expect from your normal boring everyday async/await code concerned with regular Task<T> functions that return their results in the usual way.

您绝对可以调整这些行为:

You absolutely can tweak these behaviours:

  • 您可以放弃上下文捕获通过调用 ConfigureAwait(false)你的等待.由于未捕获上下文,因此上下文附带的所有内容都将丢失,包括在原始线程上恢复的能力(对于与线程相关的上下文).

  • You can waive the context capturing by calling ConfigureAwait(false) with your awaits. Since the context is not captured, everything that comes with the context is lost, including the ability to resume on the original thread (for contexts that are concerned with threads).

即使您不使用 ConfigureAwait(false),您也可以设计异步代码,故意在线程之间切换.Raymond Chen 的博客(第 1 部分第 2 部分) 并展示了如何显式跳转到中间有一个方法

You can devise async code that purposely switches you between threads even when you are not using ConfigureAwait(false). A good example can be found in Raymond Chen's blog (part 1, part 2) and shows how to explicitly jump on another thread in the middle of a method with

await ThreadSwitcher.ResumeBackgroundAsync();

然后回来

await ThreadSwitcher.ResumeForegroundAsync(Dispatcher);

  • 因为整个 async/await 机制是松散耦合的(您可以await 任何对象定义了一个 GetAwaiter() 方法),你可以想出一个对象,它的 GetAwaiter() 对当前线程/上下文做任何你想做的事情(事实上,这正是上面的项目符号).

  • Because the entire async/await mechanism is loosely coupled (you can await any object that defines a GetAwaiter() method), you can come up with an object whose GetAwaiter() does whatever you want with current thread/context (in fact, that is exactly what the above bullet item is).

    SynchronizationContext.Current 不会神奇地将它的方式强加于其他人的代码:它是相反的.SynchronizationContext.Current 只因为Task 选择尊重它.你可以自由地实现一个忽略它的不同的等待.

    SynchronizationContext.Current does not magically enforce its ways on other people's code: it is the other way round. SynchronizationContext.Current only has effect because the implementation of Task<T> chooses to respect it. You are free to implement a different awaitable that ignores it.

    这篇关于特别是在 Unity 中,“where"是指等待从字面上返回吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆