[英]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:一个简单的例子是生成一些程序网格:
That was an interesting question, I hope I've answered it !这是一个有趣的问题,我希望我已经回答了!
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.