Job System最近在Unity2018.1中首次亮相,并将开始改变所有Unity脚本的编写方式。与即将推出的ECS和Burst编译器一起,旧的基于行为的编程范式将最终被取代。今天的文章是关于如何开始学习编写Unity脚本的新方法的教程。
任何blittable类型和值类型都可以用于任何job中。类型既是可blittable类型又是值类型,则必须是一个原始(例如int)、枚举、指针,或仅包含原始、枚举、指针和blittable结构的结构体。
这个定义排除了所有引用类型。这意味着作业不能使用类、接口、委托、动态类型、字符串和(托管)数组。本机集合,如NativeArray和NativeSlice,可以在Job中使用。还可以使用定制的本机集合类型,类似NativeHashMap的更多类型将在Unity的未来版本中可用,特别是与ECS(实体-组件-系统),后者目前处于“预览”状态。
由于jobs离开了主线程,他们不能访问Unity API的大部分。只能使用Unity API的特定部分。据我所知,截至2018.1,唯一有文档记录的安全的非实验性API是Transform,它必须通过TransformAccess和TransformAccessArray访问。下面我们将看到如何做到这一点。除了这个文档化的API,我们还可以通过Unity的c#源代码找到更多可以在主线程之外使用的功能。搜索[ThreadSafe]属性或者IsThreadSafe设置为true的[FreeFunction]属性可以找到很多有用的函数。 截至2018.1.0f2,以下是所有线程安全的函数:
UnityEngine.CoreModule/UnityEngine.iOS/Device.cs- public static extern void SetNoBackupFlag(string path); UnityEngine.CoreModule/UnityEngine.iOS/Device.cs- public static extern void ResetNoBackupFlag(string path); UnityEngine.CoreModule/UnityEngine.iOS/Device.cs- public static extern bool RequestStoreReview(); UnityEngine.CoreModule/UnityEngine.iOS/NotificationHelper.cs- internal static extern void DestroyLocal(IntPtr target); UnityEngine.CoreModule/UnityEngine.iOS/NotificationHelper.cs- internal static extern void DestroyRemote(IntPtr target); UnityEngine.CoreModule/UnityEngine.iOS/OnDemandResourcesRequest.cs- private static extern void DestroyFromScript(IntPtr ptr); UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- private Quaternion GetRotation() UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- private Vector3 GetLossyScale() UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- private bool IsIdentity() UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- private float GetDeterminant() UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- private FrustumPlanes DecomposeProjection() UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- public bool ValidTRS() UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static AtomicSafetyHandle Create() UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static AtomicSafetyHandle GetTempUnsafePtrSliceHandle() UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static void Release(AtomicSafetyHandle handle) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static extern void UseSecondaryVersion(ref AtomicSafetyHandle handle); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static void SetAllowSecondaryVersionWriting(AtomicSafetyHandle handle, bool allowWriting) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static EnforceJobResult EnforceAllBufferJobsHaveCompleted(AtomicSafetyHandle handle) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static EnforceJobResult EnforceAllBufferJobsHaveCompletedAndRelease(AtomicSafetyHandle handle) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static EnforceJobResult EnforceAllBufferJobsHaveCompletedAndDisableReadWrite(AtomicSafetyHandle handle) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static int GetReaderArray(AtomicSafetyHandle handle, int maxCount, IntPtr output) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static JobHandle GetWriter(AtomicSafetyHandle handle) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static string GetReaderName(AtomicSafetyHandle handle, int readerIndex) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static string GetWriterName(AtomicSafetyHandle handle) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- private static extern int GetFieldOffsetInStruct(FieldInfo field); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- private static extern int GetFieldOffsetInClass(FieldInfo field); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void* PinGCObjectAndGetAddress(object target, out ulong gcHandle); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public static extern void ReleaseGCObject(ulong gcHandle); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void CopyObjectAddressToPtr(object target, void* dstPtr); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void* Malloc(long size, int alignment, Allocator allocator); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void Free(void* memory, Allocator allocator); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void MemCpy(void* destination, void* source, long size); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void MemCpyReplicate(void* destination, void* source, int size, int count); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void MemCpyStride(void* destination, int destinationStride, void* source, int sourceStride, int elementSize, int count); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void MemMove(void* destination, void* source, long size); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public unsafe static extern void MemClear(void* destination, long size); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public static extern int SizeOf(Type type); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- public static extern bool IsBlittable(Type type); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/UnsafeUtility.cs- internal static extern void LogError(string msg, string filename, int linenumber); UnityEngine.CoreModule/UnityEngine/Bounds.cs- public bool Contains(Vector3 point) UnityEngine.CoreModule/UnityEngine/Bounds.cs- public float SqrDistance(Vector3 point) UnityEngine.CoreModule/UnityEngine/Bounds.cs- private static bool IntersectRayAABB(Ray ray, Bounds bounds, out float dist) UnityEngine.CoreModule/UnityEngine/Bounds.cs- public Vector3 ClosestPoint(Vector3 point) UnityEngine.CoreModule/UnityEngine/MaterialPropertyBlock.cs- private static extern void DestroyImpl(IntPtr mpb); UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static extern int ClosestPowerOfTwo(int value); UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static extern bool IsPowerOfTwo(int value); UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static extern int NextPowerOfTwo(int value); UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static extern float GammaToLinearSpace(float value); UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static extern float LinearToGammaSpace(float value); UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static Color CorrelatedColorTemperatureToRGB(float kelvin) UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static extern ushort FloatToHalf(float val); UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static extern float HalfToFloat(ushort val); UnityEngine.CoreModule/UnityEngine/Mathf.cs- public static extern float PerlinNoise(float x, float y); UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- public static Matrix4x4 TRS(Vector3 pos, Quaternion q, Vector3 s) UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- public static Matrix4x4 Inverse(Matrix4x4 m) UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- public static Matrix4x4 Transpose(Matrix4x4 m) UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- public static Matrix4x4 Ortho(float left, float right, float bottom, float top, float zNear, float zFar) UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- public static Matrix4x4 Perspective(float fov, float aspect, float zNear, float zFar) UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- public static Matrix4x4 LookAt(Vector3 from, Vector3 to, Vector3 up) UnityEngine.CoreModule/UnityEngine/Matrix4x4.cs- public static Matrix4x4 Frustum(float left, float right, float bottom, float top, float zNear, float zFar) UnityEngine.CoreModule/UnityEngine/MonoBehaviour.cs- private static extern void ConstructorCheck([Writable] Object self); UnityEngine.CoreModule/UnityEngine/Object.cs- private static extern int GetOffsetOfInstanceIDInCPlusPlusObject(); UnityEngine.CoreModule/UnityEngine/Object.cs- private static extern bool CurrentThreadIsMainThread(); UnityEngine.CoreModule/UnityEngine/Object.cs- internal static extern bool DoesObjectWithInstanceIDExist(int instanceID); UnityEngine.CoreModule/UnityEngine/Ping.cs- private static extern void Internal_Destroy(IntPtr ptr); UnityEngine.CoreModule/UnityEngine/Quaternion.cs- public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- public static Quaternion Inverse(Quaternion rotation) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- public static Quaternion Slerp(Quaternion a, Quaternion b, float t) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- public static Quaternion SlerpUnclamped(Quaternion a, Quaternion b, float t) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- public static Quaternion Lerp(Quaternion a, Quaternion b, float t) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- public static Quaternion LerpUnclamped(Quaternion a, Quaternion b, float t) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- private static Quaternion Internal_FromEulerRad(Vector3 euler) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- private static Vector3 Internal_ToEulerRad(Quaternion rotation) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- private static void Internal_ToAxisAngleRad(Quaternion q, out Vector3 axis, out float angle) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- public static Quaternion AngleAxis(float angle, Vector3 axis) UnityEngine.CoreModule/UnityEngine/Quaternion.cs- public static Quaternion LookRotation(Vector3 forward, [DefaultValue("Vector3.up")] Vector3 upwards) UnityEngine.CoreModule/UnityEngine/Screen.cs- Width { get; } UnityEngine.CoreModule/UnityEngine/Screen.cs- Height { get; } UnityEngine.CoreModule/UnityEngine/ScriptableObject.cs- private static extern void CreateScriptableObject([Writable] ScriptableObject self); UnityEngine.CoreModule/UnityEngine/UnityLogWriter.cs- private static extern void WriteStringToUnityLogImpl(string s); UnityEngine.CoreModule/UnityEngine/Vector3.cs- public static Vector3 Slerp(Vector3 a, Vector3 b, float t) UnityEngine.CoreModule/UnityEngine/Vector3.cs- public static Vector3 SlerpUnclamped(Vector3 a, Vector3 b, float t) UnityEngine.CoreModule/UnityEngine/Vector3.cs- private static extern void OrthoNormalize2(ref Vector3 a, ref Vector3 b); UnityEngine.CoreModule/UnityEngine/Vector3.cs- private static extern void OrthoNormalize3(ref Vector3 a, ref Vector3 b, ref Vector3 c); UnityEngine.CoreModule/UnityEngine/Vector3.cs- public static Vector3 RotateTowards(Vector3 current, Vector3 target, float maxRadiansDelta, float maxMagnitudeDelta) UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccessArray.cs- internal static extern IntPtr GetSortedTransformAccess(IntPtr transformArrayIntPtr); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccessArray.cs- internal static extern IntPtr GetSortedToUserIndex(IntPtr transformArrayIntPtr); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void GetPosition(ref TransformAccess access, out Vector3 p); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void SetPosition(ref TransformAccess access, ref Vector3 p); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void GetRotation(ref TransformAccess access, out Quaternion r); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void SetRotation(ref TransformAccess access, ref Quaternion r); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void GetLocalPosition(ref TransformAccess access, out Vector3 p); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void SetLocalPosition(ref TransformAccess access, ref Vector3 p); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void GetLocalRotation(ref TransformAccess access, out Quaternion r); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void SetLocalRotation(ref TransformAccess access, ref Quaternion r); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void GetLocalScale(ref TransformAccess access, out Vector3 r); UnityEngine.CoreModule/UnityEngine.Jobs/TransformAccess.cs- private static extern void SetLocalScale(ref TransformAccess access, ref Vector3 r); UnityEngine.CoreModule/Unity.Jobs.LowLevel.Unsafe/JobsUtility.cs- public static extern bool GetWorkStealingRange(ref JobRanges ranges, int jobIndex, out int beginIndex, out int endIndex); UnityEngine.CoreModule/Unity.Jobs.LowLevel.Unsafe/JobsUtility.cs- public unsafe static extern void PatchBufferMinMaxRanges(IntPtr bufferRangePatchData, void* jobdata, int startIndex, int rangeSize); UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static void SetAllowReadOrWriteAccess(AtomicSafetyHandle handle, bool allowReadWriteAccess) UnityEngine.CoreModule/Unity.Collections.LowLevel.Unsafe/AtomicSafetyHandle.cs- public static bool GetAllowReadOrWriteAccess(AtomicSafetyHandle handle) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static extern bool HasNodePool(IntPtr navMeshQuery); UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private unsafe static PathQueryStatus BeginFindPath(IntPtr navMeshQuery, NavMeshLocation start, NavMeshLocation end, int areaMask, void* costs) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static extern PathQueryStatus UpdateFindPath(IntPtr navMeshQuery, int iterations, out int iterationsPerformed); UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static extern PathQueryStatus EndFindPath(IntPtr navMeshQuery, out int pathSize); UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private unsafe static extern int GetPathResult(IntPtr navMeshQuery, void* path, int maxPath); UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static bool IsValidPolygon(IntPtr navMeshQuery, PolygonId polygon) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static int GetAgentTypeIdForPolygon(IntPtr navMeshQuery, PolygonId polygon) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static bool IsPositionInPolygon(IntPtr navMeshQuery, Vector3 position, PolygonId polygon) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static PathQueryStatus GetClosestPointOnPoly(IntPtr navMeshQuery, PolygonId polygon, Vector3 position, out Vector3 nearest) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static NavMeshLocation MapLocation(IntPtr navMeshQuery, Vector3 position, Vector3 extents, int agentTypeID, int areaMask = -1) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private unsafe static extern void MoveLocations(IntPtr navMeshQuery, void* locations, void* targets, void* areaMasks, int count); UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private unsafe static extern void MoveLocationsInSameAreas(IntPtr navMeshQuery, void* locations, void* targets, int count, int areaMask); UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static NavMeshLocation MoveLocation(IntPtr navMeshQuery, NavMeshLocation location, Vector3 target, int areaMask) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static bool GetPortalPoints(IntPtr navMeshQuery, PolygonId polygon, PolygonId neighbourPolygon, out Vector3 left, out Vector3 right) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static Matrix4x4 PolygonLocalToWorldMatrix(IntPtr navMeshQuery, PolygonId polygon) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static Matrix4x4 PolygonWorldToLocalMatrix(IntPtr navMeshQuery, PolygonId polygon) UnityEngine.AIModule/UnityEngine.Experimental.AI/NavMeshQuery.cs- private static NavMeshPolyTypes GetPolygonType(IntPtr navMeshQuery, PolygonId polygon) UnityEngine.UnityAnalyticsModule/UnityEngine.Analytics/UnityAnalyticsHandler.cs- internal static extern void Internal_Destroy(IntPtr ptr); UnityEngine.UnityAnalyticsModule/UnityEngine.Analytics/CustomEventData.cs- internal static extern void Internal_Destroy(IntPtr ptr); UnityEngine.AnimationModule/UnityEngine.Animations/AnimatorControllerPlayable.cs- private static extern int StringToHash(string name); UnityEngine.UnityConnectModule/UnityEngine/RemoteConfigSettings.cs- internal static extern void Internal_Destroy(IntPtr ptr); UnityEngine.GameCenterModule/UnityEngine.SocialPlatforms.GameCenter/GcLeaderboard.cs- private static extern void GcLeaderboard_Dispose(IntPtr leaderboard); UnityEngine.IMGUIModule/UnityEngine/ObjectGUIState.cs- private static extern void Internal_Destroy(IntPtr ptr); UnityEngine.UIElementsModule/UnityEngine.CSSLayout/Native.cs- private static extern void CSSNodeFreeInternal(IntPtr cssNode); UnityEngine.UnityWebRequestModule/UnityEngine.Networking/DownloadHandler.cs- private extern void Release(); UnityEngine.UnityWebRequestModule/UnityEngine.Networking/CertificateHandler.cs- private extern void Release(); UnityEngine.UnityWebRequestModule/UnityEngine.Networking/UploadHandler.cs- private extern void Release(); UnityEngine.UnityWebRequestModule/UnityEngine.Networking/UnityWebRequest.cs- private static extern string GetWebErrorString(UnityWebRequest.UnityWebRequestError err); UnityEngine.UnityWebRequestModule/UnityEngine.Networking/UnityWebRequest.cs- private extern void Release(); UnityEngine.UnityWebRequestModule/UnityEngine.Networking/UnityWebRequest.cs- public extern void Abort(); UnityEngine.ARModule/UnityEngine.XR.Tango/MeshReconstructionServer.cs- internal static extern void DestroyThreaded(IntPtr server); UnityEngine.AnimationModule/UnityEngine/Animator.cs- public static extern int StringToHash(string name); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern void InternalSetScriptingPtr(uint providerId, AudioSampleProvider provider); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern bool InternalIsValid(uint providerId); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern uint InternalGetMaxSampleFrameCount(uint providerId); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern uint InternalGetAvailableSampleFrameCount(uint providerId); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern uint InternalGetFreeSampleFrameCount(uint providerId); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern uint InternalGetFreeSampleFrameCountLowThreshold(uint providerId); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern void InternalSetFreeSampleFrameCountLowThreshold(uint providerId, uint sampleFrameCount); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern bool InternalGetEnableSampleFramesAvailableEvents(uint providerId); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern void InternalSetEnableSampleFramesAvailableEvents(uint providerId, bool enable); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern bool InternalGetEnableSilencePadding(uint id); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern void InternalSetEnableSilencePadding(uint id, bool enabled); UnityEngine.AudioModule/UnityEngine.Experimental.Audio/AudioSampleProvider.cs- private static extern IntPtr InternalGetConsumeSampleFramesNativeFunctionPtr();注意,其中一些是私有的,因此只能通过公共API间接使用。例如,调用Debug。日志来间接调用私有的UnityLogWriter.WriteStringToUnityLogImpl。
在纯c#中还实现了一些Unity API函数。例如,Vector3。颜色。Lerp不会对引擎的本机c++代码进行任何调用。这些函数都可以在作业中使用。如果这些函数只调用线程安全的本机代码函数,也可以调用它们,如上所述和列出的。
第一步是定义Job。Job应该做少量定义良好的工作,类似于函数。首先,定义一个结构体:
public struct ApplyVelocityJob { }接下来,决定做什么样的Job。目前有三种工作可供选择:
IJob: 执行一次的简单作业IJobParallelFor: 为一系列值执行的作业IJobParallelForTransform: 能访问transforms的作业让我们从简单的IJob开始,并实现它:
public struct ApplyVelocityJob : IJob { public void Execute() { } }现在我们需要定义Job的输入和输出。为此,我们将字段添加到结构中,而不是将参数添加到其执行方法中。该Job将根据给定的运行时间范围内的相应速度修改对象的位置。让我们添加一些字段:
public struct ApplyVelocityJob : IJob { public float ElapsedTime; public NativeArray<Vector3> Positions; public NativeArray<Vector3> Velocities; public void Execute() { } }为了实现更大的优化和错误检查,我们可以选择向这些“参数”字段添加[ReadOnly]和[WriteOnly]属性:
public struct ApplyVelocityJob : IJob { [ReadOnly] public float ElapsedTime; public NativeArray<Vector3> Positions; [ReadOnly] public NativeArray<Vector3> Velocities; public void Execute() { } }最后一步是通过填写执行方法来实际实现Job的逻辑:
public struct ApplyVelocityJob : IJob { [ReadOnly] public float ElapsedTime; public NativeArray<Vector3> Positions; [ReadOnly] public NativeArray<Vector3> Velocities; public void Execute() { for (int i = 0; i < Positions.Length; ++i) { Positions[i] += Velocities[i] * ElapsedTime; } } }就是这样。然而,我们可以通过使其实现IJobParallelFor接口轻松实现并行化作业。作业系统将对数组的每个元素运行一次Execute,而不是对整个数组运行一次Execute。每次调用执行时,它可能会使用不同的CPU内核,这意味着只需进行一些简单的调整,作业就可以利用系统中的所有内核。让我们看看如何做:
public struct ApplyVelocityParallelJob : IJobParallelFor { [ReadOnly] public float ElapsedTime; public NativeArray<Vector3> Positions; [ReadOnly] public NativeArray<Vector3> Velocities; public void Execute(int index) { Positions[index] += Velocities[index] * ElapsedTime; } }由于for循环实际上已经转移到作业系统,因此编写并行版本可以说更容易,因为我们不再需要编写循环了。最后,如果我们想在作业中修改游戏对象的Transform,那么我们需要实现IJobParallelForTransform。让我们修改这个作业,使它不只是在NativeArray中使用一个Vector3,而是实际改变游戏对象的位置:
public struct ApplyVelocityTransformJob : IJobParallelForTransform { [ReadOnly] public float ElapsedTime; [ReadOnly] public NativeArray<Vector3> Velocities; public void Execute(int index, TransformAccess transform) { transform.localPosition += Velocities[index] * ElapsedTime; } }创建作业就像创建其他结构一样简单。只需调用new并填写所有字段。初始化器语法可以很方便地做到这一点:
ApplyVelocityJob job = new ApplyVelocityJob { ElapsedTime = Time.time, Positions = positions, Velocities = velocities }; ApplyVelocityParallelJob parallelJob = new ApplyVelocityParallelJob { ElapsedTime = Time.time, Positions = positions, Velocities = velocities }; ApplyVelocityTransformJob transformJob = new ApplyVelocityTransformJob { ElapsedTime = Time.time, Velocities = velocities };Jobs可以从几个方面开始。让我们从IJob开始:
JobHandle jobHandle = job.Schedule();调度作业会告诉作业系统它已经准备好开始了。我们得到一个JobHandle,我们可以用它来指代未来的作业。例如,如果我们想开始一个依赖于另一个任务完成的任务,我们可以将其传递到进度表中。例如,要运行同一个作业两次,我们可以让第二个作业在第一个作业完成后运行:
// Schedule with no dependencies JobHandle jobHandle1 = job.Schedule(); // Schedule with dependencies JobHandle jobHandle2 = job.Schedule(jobHandle1);现在让我们尝试安排一个IJobParallelFor。为此,我们需要提供一些额外的参数。第一个是循环应该运行的迭代次数。第二个是在单个核心上的“批处理”中运行的迭代次数。这不是一个正确的值,可以对小作业调得更大,对大作业调得更小。以下是日程调用的工作方式:
// Schedule with no dependencies JobHandle jobHandle1 = parallelJob.Schedule(positions.Length, 32); // Schedule with dependencies JobHandle jobHandle2 = parallelJob.Schedule(positions.Length, 32, jobHandle1);最后是IJobParallelForTransform,它接受TransformAccessArray参数。这个参数封装了一个Transform对象的托管数组,需要通过一个Dispose调用手动释放,就像NativeArray一样。以下是如何创建和安排工作的方法:
// Get or create a managed array of Transform objects Transform[] transforms = new [] { transform }; // Wrap the managed array in a TransformAccessArray TransformAccessArray accessArray = new TransformAccessArray(transforms); // Schedule with no dependencies JobHandle jobHandle1 = transformJob.Schedule(accessArray); // Schedule with dependencies JobHandle jobHandle2 = transformJob.Schedule(accessArray, jobHandle1);在安排所有作业之后还有最后一步,或者在安排下一个作业之前主线程上有大量工作要做。我们需要告诉作业系统,我们已经准备好让它开始执行预定的作业:
JobHandle.ScheduleBatchedJobs();工作通常都有日程安排和任务处理。ScheduleBatchedJobs,但是IJob和IJobParallelFor也可以同步运行,以便在继续之前立即完成。这不是IJobParallelForTransform的选项。在执行此操作时,我们使用不同的参数调用Run,并且不涉及依赖项。以下是如何以这种方式管理工作:
job.Run(); parallelJob.Run(positions.Length);