首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >UnityMainThreadDispatcher是做什么的?

UnityMainThreadDispatcher是做什么的?
EN

Stack Overflow用户
提问于 2019-10-20 02:00:58
回答 1查看 4.3K关注 0票数 6

我读过这段代码。

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

在代码的第62行周围有以下描述。

这是在做什么处理?

代码语言:javascript
运行
复制
    if (UnityMainThreadDispatcher.Exists()) {
        dispatcher = UnityMainThreadDispatcher.Instance ();
    } 

GitHub上有代码,但是它是统一中的一个标准特性吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-20 06:34:26

这里是为什么您需要一个伪调度程序 in Unity:

在统一中,大多数对象只能在主统一线程中创建。

但是,假设您需要在后台运行一些繁重的任务,比如使用Task.Run,那么在您的任务中,您将无法像前面那样实例化这些对象,但仍然希望如此。

解决这个问题有很多种解决方案,但它们都利用了相同的东西:

捕获统一的同步上下文并向其发送消息

,这是一种原创的方法,灵感来源于雷蒙德·陈的“旧的新事物:

C++/WinRT嫉妒:将线程切换任务引入C# (WPF和WinForms版本)

其概念如下:在方法中的任何时候切换到特定的线程!

公共类型

IThreadSwitcher:

代码语言:javascript
运行
复制
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:

代码语言:javascript
运行
复制
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();
        }
    }
}

私有类型

ThreadSwitcherTask:

代码语言:javascript
运行
复制
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:

代码语言:javascript
运行
复制
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:

代码语言:javascript
运行
复制
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;
        }
    }
}

示例

尽管它是一种奇特的方法,但它有着巨大的优势,即通过使用单个调用,您可以在相同的方法中在不同的线程中工作。下面的代码是用Task.Run执行的,但是在实例化Unity时不会产生任何错误,因为它是在正确的线程中完成的。

代码语言:javascript
运行
复制
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);
    }
}

现在由您来仔细划分您的工作,因为从本质上说,统一同步上下文并不意味着要运行大量的计算,而只是实例化您无法从另一个线程中运行的内容。

一个简单的例子是生成一些过程网格:

  • 在您的任务中完成所有的数学运算,并生成足够的数据来创建网格。
    • 即顶点、法线、颜色、uvs

  • 切换到统一线程
    • 从这些数据创建一个网格,在此期间,这将足够快,以至于无法察觉。

这是一个有趣的问题,我希望我已经回答了!

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58469468

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档