简体   繁体   English

UnityMainThreadDispatcher 是做什么的?

[英]What does UnityMainThreadDispatcher do?

I read this code.我读了这段代码。

https://github.com/johnjcsmith/iPhoneMoCapUnity/blob/master/Assets/NetworkMeshAnimator.cs https://github.com/johnjcsmith/iPhoneMoCapUnity/blob/master/Assets/NetworkMeshAnimator.cs

There is the following description around the 62nd line of the code.在代码的第 62 行周围有以下描述。

What kind of processing is this doing?这是在做什么处理?

    if (UnityMainThreadDispatcher.Exists()) {
        dispatcher = UnityMainThreadDispatcher.Instance ();
    } 

There is code on GitHub, but is it a standard feature in Unity? GitHub 上有代码,但它是 Unity 的标准功能吗?

Here's why you need a pseudo dispatcher in Unity:这就是为什么您需要在 Unity 中使用伪调度程序的原因:

In Unity, most objects can only be created from within main Unity thread.在 Unity 中,大多数对象只能在 Unity 主线程中创建。

But suppose you have some heavy task you'd like to run in background such as with Task.Run , in your task you wouldn't be able to instantiate such objects as aforementioned but still would like to.但是假设您有一些繁重的任务想要在后台运行,例如使用Task.Run ,在您的任务中,您将无法实例化上述但仍然希望的对象。

There are quite a couple of solutions in solving this problem but they all leverage the same thing:解决这个问题有很多解决方案,但它们都利用相同的东西:

Capturing Unity's synchronization context and posting messages to it捕获 Unity 的同步上下文并向其发布消息

Here's an original way in doing so, inspired from Raymond Chen's The Old New Thing:这是一个原始的方法,灵感来自 Raymond Chen 的 The Old New Thing:

C++/WinRT envy: Bringing thread switching tasks to C# (WPF and WinForms edition) C++/WinRT羡慕:给C#(WPF和WinForms版)带来线程切换任务

The concept is the following: switch to a specific thread at any time in a method !概念如下:在方法中随时切换到特定线程!

Public types公共类型

IThreadSwitcher:线程切换器:

using System.Runtime.CompilerServices;
using JetBrains.Annotations;

namespace Threading
{
    /// <summary>
    ///     Defines an object that switches to a thread.
    /// </summary>
    [PublicAPI]
    public interface IThreadSwitcher : INotifyCompletion
    {
        bool IsCompleted { get; }

        IThreadSwitcher GetAwaiter();

        void GetResult();
    }
}

ThreadSwitcher:线程切换器:

using Threading.Internal;

namespace Threading
{
    /// <summary>
    ///     Switches to a particular thread.
    /// </summary>
    public static class ThreadSwitcher
    {
        /// <summary>
        ///     Switches to the Task thread.
        /// </summary>
        /// <returns></returns>
        public static IThreadSwitcher ResumeTaskAsync()
        {
            return new ThreadSwitcherTask();
        }

        /// <summary>
        ///     Switch to the Unity thread.
        /// </summary>
        /// <returns></returns>
        public static IThreadSwitcher ResumeUnityAsync()
        {
            return new ThreadSwitcherUnity();
        }
    }
}

Private types私有类型

ThreadSwitcherTask:线程切换任务:

using System;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;

namespace Threading.Internal
{
    internal struct ThreadSwitcherTask : IThreadSwitcher
    {
        public IThreadSwitcher GetAwaiter()
        {
            return this;
        }

        public bool IsCompleted => SynchronizationContext.Current == null;

        public void GetResult()
        {
        }

        public void OnCompleted([NotNull] Action continuation)
        {
            if (continuation == null)
                throw new ArgumentNullException(nameof(continuation));

            Task.Run(continuation);
        }
    }
}

ThreadSwitcherUnity:线程切换器统一:

using System;
using System.Threading;
using JetBrains.Annotations;

namespace Threading.Internal
{
    internal struct ThreadSwitcherUnity : IThreadSwitcher
    {
        public IThreadSwitcher GetAwaiter()
        {
            return this;
        }

        public bool IsCompleted => SynchronizationContext.Current == UnityThread.Context;

        public void GetResult()
        {
        }

        public void OnCompleted([NotNull] Action continuation)
        {
            if (continuation == null)
                throw new ArgumentNullException(nameof(continuation));

            UnityThread.Context.Post(s => continuation(), null);
        }
    }
}

UnityThread:统一线程:

using System.Threading;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;

#endif

namespace Threading.Internal
{
    internal static class UnityThread
    {
#pragma warning disable IDE0032 // Use auto property
        private static SynchronizationContext _context;
#pragma warning restore IDE0032 // Use auto property

        public static SynchronizationContext Context => _context;

#if UNITY_EDITOR
        [InitializeOnLoadMethod]
#endif
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        private static void Capture()
        {
            _context = SynchronizationContext.Current;
        }
    }
}

Example例子

Albeit it is an exotic approach it has huge advantages, namely that by using a single call you can do work in different threads in the same method.尽管它是一种奇特的方法,但它具有巨大的优势,即通过使用单个调用,您可以在同一方法中的不同线程中工作。 The following code is executed with Task.Run but won't produce any errors while instantiating Unity objects since it's done in the right thread.以下代码使用Task.Run执行,但在实例化 Unity 对象时不会产生任何错误,因为它是在正确的线程中完成的。

private static async Task DoWork(CancellationToken token)
{
    token.ThrowIfCancellationRequested();

    var gameObjects = new List<GameObject>();

    await ThreadSwitcher.ResumeUnityAsync();

    for (var i = 0; i < 25; i++)
    {
        if (token.IsCancellationRequested)
            token.ThrowIfCancellationRequested();

        await Task.Delay(125, token);

        var gameObject = new GameObject(i.ToString());

        gameObjects.Add(gameObject);
    }
}

Now it's up to you to finely slice your work since by nature Unity synchronization context is not meant to run heavy computation, rather, just instantiate stuff you wouldn't be able to from another thread.现在由您来对您的工作进行精细分割,因为 Unity 同步上下文本质上并不意味着运行繁重的计算,而是仅实例化您无法从另一个线程执行的内容。

A simple example would be generating some procedural mesh:一个简单的例子是生成一些程序网格:

  • do all your maths in your task and produce enough data to create a mesh在你的任务中做所有的数学运算并产生足够的数据来创建一个网格
    • ie vertices, normals, colors, uvs即顶点、法线、colors、uvs
  • switch to Unity thread切换到 Unity 线程
    • create a mesh from this data, PERIOD, this will be fast enough to be non-perceptible根据这些数据创建一个网格,PERIOD,这将足够快以至于无法察觉

That was an interesting question, I hope I've answered it !这是一个有趣的问题,我希望我已经回答了!

No, its not a Unity thing.不,它不是 Unity 的东西。

It's from this package on Github.它来自Github上的 package。 Which, for reference, I found as the first result on Google when I searched for it.作为参考,当我搜索它时,我在谷歌上发现了它的第一个结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM