具体地,在Unity中,“在哪里"是指.从字面上返回到等待? [英] In Unity specifically, "where" does an await literally return to?

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

问题描述

在Unity中,说您有一个GameObject.因此,可能是劳拉·克罗夫特(Lara Croft),马里奥(Mario),愤怒的鸟,特定的立方体,特定的树或其他任何东西.

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不是OO,它是ECS.您可以附加"到GameObjectComponent本身可能是也可能不是用OO语言创建的,但是Unity本身只是一个列表. GameObject和一个在每个帧上对其运行任何Component的框架引擎.因此,实际上Unity当然是完全"单线程的,甚至没有一种概念上的方式来做与实际Unity"有关的事情( 游戏对象列表")在另一个 1 线程上.)

(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.)

所以说在多维数据集上,我们有一个名为Component的Test

So say on the cube we have a Component called Test

public class Test: MonoBehaviour {

它确实具有Update伪函数,因此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在各种游戏对象上运行所有Update调用.

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中并且仅在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.

例如 WindowsFormsSynchronizationContext 将确保在await之后在GUI线程上开始的执行将在GUI线程上继续执行,因此,如果在WinForms应用程序中执行测试,则将看到ManagedThreadId.

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>函数有关的正常无聊的日常async/await代码中得到的期望,这些常规c 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:

  • 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);

  • 因为整个异步/等待机制都是松散耦合的(您可以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<T> 选择尊重.您可以自由地实现另一个可以忽略它的等待状态.

    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中,“在哪里"是指.从字面上返回到等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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