tai*_*chi 6 c# multithreading unity-game-engine
我读了这段代码。
https://github.com/johnjcsmith/iPhoneMoCapUnity/blob/master/Assets/NetworkMeshAnimator.cs
代码的第 62 行周围有以下说明。
这是在做什么处理?
if (UnityMainThreadDispatcher.Exists()) {
dispatcher = UnityMainThreadDispatcher.Instance ();
}
Run Code Online (Sandbox Code Playgroud)
GitHub 上有代码,但它是 Unity 中的标准功能吗?
这就是为什么您需要在 Unity 中使用伪调度程序的原因:
在 Unity 中,大多数对象只能从 Unity 主线程中创建。
但是假设您有一些繁重的任务想要在后台运行,例如 with 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();
}
}
Run Code Online (Sandbox Code Playgroud)
线程切换器:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
私有类型
线程切换任务:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
统一线程:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
例子
尽管它是一种奇特的方法,但它具有巨大的优势,即通过使用单个调用,您可以在同一方法的不同线程中进行工作。以下代码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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在由您来细分您的工作,因为本质上 Unity 同步上下文并不意味着运行繁重的计算,而只是实例化您无法从另一个线程执行的内容。
一个简单的例子是生成一些程序网格:
这是一个有趣的问题,我希望我已经回答了!