簡體   English   中英

UnityMainThreadDispatcher 是做什么的?

[英]What does UnityMainThreadDispatcher do?

我讀了這段代碼。

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

在代碼的第 62 行周圍有以下描述。

這是在做什么處理?

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

GitHub 上有代碼,但它是 Unity 的標准功能嗎?

這就是為什么您需要在 Unity 中使用偽調度程序的原因:

在 Unity 中,大多數對象只能在 Unity 主線程中創建。

但是假設您有一些繁重的任務想要在后台運行,例如使用Task.Run ,在您的任務中,您將無法實例化上述但仍然希望的對象。

解決這個問題有很多解決方案,但它們都利用相同的東西:

捕獲 Unity 的同步上下文並向其發布消息

這是一個原始的方法,靈感來自 Raymond Chen 的 The Old New Thing:

C++/WinRT羡慕:給C#(WPF和WinForms版)帶來線程切換任務

概念如下:在方法中隨時切換到特定線程!

公共類型

線程切換器:

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();
    }
}

線程切換器:

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();
        }
    }
}

私有類型

線程切換任務:

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

線程切換器統一:

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

統一線程:

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 對象時不會產生任何錯誤,因為它是在正確的線程中完成的。

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

現在由您來對您的工作進行精細分割,因為 Unity 同步上下文本質上並不意味着運行繁重的計算,而是僅實例化您無法從另一個線程執行的內容。

一個簡單的例子是生成一些程序網格:

  • 在你的任務中做所有的數學運算並產生足夠的數據來創建一個網格
    • 即頂點、法線、colors、uvs
  • 切換到 Unity 線程
    • 根據這些數據創建一個網格,PERIOD,這將足夠快以至於無法察覺

這是一個有趣的問題,我希望我已經回答了!

不,它不是 Unity 的東西。

它來自Github上的 package。 作為參考,當我搜索它時,我在谷歌上發現了它的第一個結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM