Unity 之 Pure版Entity Component System (ECS)  官方Rotation示例解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 又有一段时间没有写博客了,真是不爽~~~ 趁着最近两天没事,赶紧补上一篇,这次开始写一篇Pure ECS版本示例解析,对上次Hybrid版本Unity之浅析 Entity Component System (ECS)的补充,使用的是官方案例的Rotation场景。

又有一段时间没有写博客了,真是不爽~~~ 趁着最近两天没事,赶紧补上一篇,这次开始写一篇Pure ECS版本示例解析,对上次Hybrid版本Unity之浅析 Entity Component System (ECS)的补充,使用的是官方案例的Rotation场景。


有说错或不准确的地方欢迎留言指正


Unity版本 208.2.3f1 Entities 版本 preview.8

img_cbc1e8443b69544675b4822d50462d56.png

ECS虽然现在已经实装,但还在实验阶段,笔者在开发的过程中也遇到了一些IDE卡顿,Unity编辑器崩溃的情况。这个情况相信在Unity后续版本中会得到改善。

这么多问题为什么还要用呢?那就是计算速度快!!!真的很快,笔者这垃圾笔记本此场景创建20W个Cube还能保持在20帧左右,所以可见一斑。

主要参考官方文档地址

对应工程文件下载


  • 2018/08/29更新 添加 [BurstComplie]特性 以后如果你打开Burst Complier的话,下面的代码会在编译的时候被Burst Compiler优化,运行速度更快,目前Burst只是运行在编辑器模式下,之后正式出了会支持编译

效果展示

img_f55caf17fce8063e99c49dee9721ad7e.gif

下面笔者会逐步创建示例中的场景,使用Unity版本2018.2.3f1 ,基本配置请参考Unity之浅析 Entity Component System (ECS)

首选需要准备的资源为:

  • Unity对应Logo模型
  • 一个在场景中对应的Logo Object
  • 一个产卵器,生产指定Cube按照规定半径随机分布

创建Unity对应Logo模型

在hierarchy中创建一个gameObject命名为RotationLogo然后添加组下组件,这些组件都是ECS自带的

img_ab9bf522a42d8c97942674987cb52f8d.png
  • GameObjectEntity 必带组件,没有的话ECS系统不识别
  • PositionComponent 组件对应传统模式中 transform.position
  • CopyInitialTransformFromGameObjectComponent 初始化TransformMatrix中的数据
  • TransformMatrix 指定应该存储一个4x4矩阵。这个矩阵是根据位置的变化自动更新的【直译官方文档】
  • MeshInstanceRendererComponent可以理解为原来的Mesh Filter与Mesh Renderer结合体,且大小不受tranform中Scale数值控制
  • MoveSpeedComponent也是官方自带组件,因为ECS主要是面向数据编程,此组件仅仅代表一个运行速度的数据

注意:MeshInstanceRendererComponent中需要Mesh是指定使用哪个网格,对应的Material需要勾选Enable GPU Instancing

img_e5b1593c7c821b5662b7246c8142c0ee.png
img_32ad3a7f871aec9f2dc19922a11b768e.png

创建一个产卵器,生产指定Cube按照规定半径随机分布

在hierarchy中创建一个gameObject命名为RotatingCubeSpawner然后添加如下组件,这些组件都是ECS自带的,这里没有使用TransformMatrix 组件,因为TransformMatrix 组件需要配合其他组件或系统使用,例如MeshInstanceRenderer,这里RotatingCubeSpawner仅仅是一个产卵触发,所以不需要。

img_f6c2a32aeaf02da59d3f8fc4842a1199.png

创建脚本 SpawnRandomCircleComponent ,然后添加到RotatingCubeSpawner上

img_4d61dca92dd4115f72030708fc1a4bac.png
using System;
using Unity.Entities;
using UnityEngine;


/// <summary>
/// 使用ISharedComponentData可显著降低内存
/// </summary>
[Serializable]
public struct SpawnRandomCircle : ISharedComponentData//使用ISharedComponentData可显著降低内存
{
    //预制方块
    public GameObject prefab;
    public bool spawnLocal;
    //生成的半径
    public float radius;
    //生成物体个数
    public int count;
}

/// <summary>
/// 包含方块的个数个生成半径等
/// </summary>
public class SpawnRandomCircleComponent : SharedComponentDataWrapper<SpawnRandomCircle> { }

在传统模式中,我们能把脚本挂到gameObejc上是因为继承了MonoBehaviour,但是在Pure ECS版本中,如需要的数据挂在对应的Object上,创建的类需要继承SharedComponentDataWrapperComponentDataWrapper,包含的数据(struct)需要继承ISharedComponentDataIComponentData
这里大家可能有疑问了,既然都能创建挂载为什么出现两个类?使用SharedComponentDataWrapper与ISharedComponentData可显著降低内存,创建100个cube和一个cube的消耗内存的差异几乎为零。如使用的数据仅仅是读取,或很少的改变,且在同Group中(后续示例中有展示),使用SharedComponentData是一个不错的选择。


接下来开始编写Logo模型旋转所需的额外数据

按照示例显示,Logo图标在一个指定的位置以规定的半径旋转,在Logo一定范围的cube会触发旋转效果

创建如下数据添加到Object上

img_7ed504ff967763385a90faa4317e475a.png
旋转中心点和对应半径的数据
using System;
using Unity.Entities;
using Unity.Mathematics;

/// <summary>
/// 转动Logo的中心点和转动半径
/// </summary>
[Serializable]
public struct MoveAlongCircle : IComponentData
{
    //Logo对应的中心点
    public float3 center;
    //Logo对应的半径
    public float radius;
    //运行时间
    //[NonSerialized]
    public float t;
}
/// <summary>
/// 转动Logo的中心点和转动半径
/// </summary>
public class MoveAlongCircleComponent : ComponentDataWrapper<MoveAlongCircle> { }
Logo碰撞方块后给予方块重置的速度数据
using System;
using Unity.Entities;

/// <summary>
/// Logo碰撞方块后给予方块重置的速度
/// </summary>
[Serializable]
public struct RotationSpeedResetSphere : IComponentData
{
    //方块重置的速度
    public float speed;
}
/// <summary>
/// 方块旋转的速度
/// </summary>
public class RotationSpeedResetSphereComponent : ComponentDataWrapper<RotationSpeedResetSphere> { }
触发方块旋转的半径数据
using System;
using Unity.Entities;


[Serializable]
public struct Radius : IComponentData
{
    //触发方块旋转的半径
    public float radius;
}
/// <summary>
/// 触发方块旋转的半径
/// </summary>
public class RadiusComponent : ComponentDataWrapper<Radius> { }

话不多说,接下来要让Logo嗨起来! 哦不对,让Logo转起来。。。。

下面是Logo旋转的全部逻辑代码,笔者会逐步为大家解析

using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Burst;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;


//Logo运动相关逻辑
public class MoveAlongCircleSystem : JobComponentSystem
{
    // Logo运动相关逻辑中需要用到的数据
    struct MoveAlongCircleGroup
    {
        //Logo位置
        public ComponentDataArray<Position> positions;
        //旋转的中心点和半径数据
        public ComponentDataArray<MoveAlongCircle> moveAlongCircles;
        //旋转速度数据
        [ReadOnly] public ComponentDataArray<MoveSpeed> moveSpeeds;
        //固定写法
        public readonly int Length;
    }
    //注入数据 Inject自带特性
    [Inject] private MoveAlongCircleGroup m_MoveAlongCircleGroup;


    [BurstCompile]
    struct MoveAlongCirclePosition : IJobParallelFor//Logo位置旋转更新逻辑,可以理解为传统模式中的Update
    {
        /// <summary>
        /// 位置数据
        /// </summary>
        public ComponentDataArray<Position> positions;
        /// <summary>
        /// 中心点及半径数据
        /// </summary>
        public ComponentDataArray<MoveAlongCircle> moveAlongCircles;
        /// <summary>
        /// 运行速度
        /// </summary>
        [ReadOnly] public ComponentDataArray<MoveSpeed> moveSpeeds;
        /// <summary>
        /// 运行时间
        /// </summary>
        public float dt;

        /// <summary>
        /// 并行执行for循环 i 根据length计算 打印的一直是0
        /// </summary>
        /// <param name="i"></param>
        public void Execute(int i)
        {
            //Debug.Log(i); //打印的一直是0 虽然可以打印,但是会报错,希望官方会出针对 ECS 的 Debug.Log

            //运行时间
            float t = moveAlongCircles[i].t + (dt * moveSpeeds[i].speed);
            //位置偏移量
            float offsetT = t + (0.01f * i);
            float x = moveAlongCircles[i].center.x + (math.cos(offsetT) * moveAlongCircles[i].radius);
            float y = moveAlongCircles[i].center.y;
            float z = moveAlongCircles[i].center.z + (math.sin(offsetT) * moveAlongCircles[i].radius);

            moveAlongCircles[i] = new MoveAlongCircle
            {
                t = t,
                center = moveAlongCircles[i].center,
                radius = moveAlongCircles[i].radius
            };
            //更新Logo的位置
            positions[i] = new Position
            {
                Value = new float3(x, y, z)
            };
        }
    }

    //数据初始化
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var moveAlongCirclePositionJob = new MoveAlongCirclePosition();
        moveAlongCirclePositionJob.positions = m_MoveAlongCircleGroup.positions;
        moveAlongCirclePositionJob.moveAlongCircles = m_MoveAlongCircleGroup.moveAlongCircles;
        moveAlongCirclePositionJob.moveSpeeds = m_MoveAlongCircleGroup.moveSpeeds;
        moveAlongCirclePositionJob.dt = Time.deltaTime;
        return moveAlongCirclePositionJob.Schedule(m_MoveAlongCircleGroup.Length, 64, inputDeps);
    }
}

解析一
img_14a6729772370521a87d655f0fa56def.png

其中这段code 指的是需要声明一个Group 【可以理解为传统模式中组件的集合】,这里含有Logo运动相关逻辑中需要用到的数据,注入m_MoveAlongCircleGroup,可以使在unity运行时unity自动寻找符合此数据集合的物体,然后把对应的数据都注入到m_MoveAlongCircleGroup中。这样我们也就变相的找到了Logo物体

解析二
img_32969760c8f0099c6dd43be47991b5dc.png

struct MoveAlongCirclePosition : IJobParallelFor代码块中的Execute,可以理解为传统模式中的Update,不过是并行执行的。相关逻辑就是计算运行时间、运算位置并赋值。

以为这就完了,并没有,看下面

解析三
img_1f6bf32ddc3846872f5b6ce2abe10b1b.png

想要把MoveAlongCirclePosition中的变量和我们找到的物体联系起来,且在Job系统中并行执行就需要JobHandle OnUpdate。他的作用是把我们包装起来的业务逻辑【就是Execute】放到Job系统执行【多核心并行计算】,并且把找到的物体和MoveAlongCirclePosition中的变量关联起来。

下面我们要让产卵器动起来

准备产卵器中预制体

在hierarchy中创建一个gameObject命名为RotatingCube然后添加如下组件

img_655e99f3ac71d78deaf4f839d0409978.png

除官方自带组件外添加额外组件RotationSpeedComponent和RotationAccelerationComponent,分别代表cube实时的旋转速度和cube速度衰减的加速度

实时的旋转速度 数据
using System;
using Unity.Entities;

/// <summary>
/// 方块自身速度
/// </summary>
[Serializable]
public struct RotationSpeed : IComponentData
{
    public float Value;
}
public class RotationSpeedComponent : ComponentDataWrapper<RotationSpeed> { }

速度衰减的加速度 数据
using System;
using Unity.Entities;
/// <summary>
/// 方块的加速度 -1 速度逐渐变慢
/// </summary>
[Serializable]
public struct RotationAcceleration : IComponentData
{
    public float speed;
}
public class RotationAccelerationComponent : ComponentDataWrapper<RotationAcceleration> { }

然后把预制体拖拽到指定的产卵器中,设置好数据

img_31dfe43a7530da8b2b08fa8d8ebf7eb8.png

产卵Cube全部Code

using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

//产卵器系统相关逻辑
public class SpawnRandomCircleSystem : ComponentSystem
{
    //对应产卵器的组件集合
    struct Group
    {
        //含有产卵所需的 个数、半径、预制体数据
        [ReadOnly] public SharedComponentDataArray<SpawnRandomCircle> Spawner;
        //产卵器位置数据
        public ComponentDataArray<Position> Position;
        //产卵器对应的 GameObject Entity 实体
        public EntityArray Entity;
        //因为目前产卵器只有一个,所以其 Length 数值为 1
        public readonly int Length;
    }
    //注入组件集合
    [Inject] Group m_Group;


    protected override void OnUpdate()
    {

        while (m_Group.Length != 0)
        {
            var spawner = m_Group.Spawner[0];
            var sourceEntity = m_Group.Entity[0];
            var center = m_Group.Position[0].Value;

            //根据产卵的个数声明对应个数的 entities 数组
            var entities = new NativeArray<Entity>(spawner.count, Allocator.Temp);
            //实例化cube
            EntityManager.Instantiate(spawner.prefab, entities);
            //创建对应的position数组(个数等于cube创建个数)
            var positions = new NativeArray<float3>(spawner.count, Allocator.Temp);

            if (spawner.spawnLocal)
            {
                //计算出每一个Cube对应的Position位置 使用 ref 填充
                GeneratePoints.RandomPointsOnCircle(new float3(), spawner.radius, ref positions);

                //遍历Position赋值
                for (int i = 0; i < spawner.count; i++)
                {
                    var position = new LocalPosition
                    {
                        Value = positions[i]
                    };
                    //为每一个Entity赋值
                    EntityManager.SetComponentData(entities[i], position);
                    //因为选择的是spawnLocal,所以要为对应的 entity添加 TransformParent(类似于原来的 transform.SetParent)
                    EntityManager.AddComponentData(entities[i], new TransformParent { Value = sourceEntity });
                }
            }
            else
            {
                GeneratePoints.RandomPointsOnCircle(center, spawner.radius, ref positions);
                for (int i = 0; i < spawner.count; i++)
                {
                    var position = new Position
                    {
                        Value = positions[i]
                    };
                    EntityManager.SetComponentData(entities[i], position);
                }
            }

            entities.Dispose();
            positions.Dispose();

            EntityManager.RemoveComponent<SpawnRandomCircle>(sourceEntity);

            //实例化 & AddComponent和RemoveComponent调用使注入的组无效,
            //所以在我们进入下一个产卵之前我们必须重新注入它们
            UpdateInjectedComponentGroups();
        }
    }
}
解析一
img_10208d59867861f786abe972e0bf44ac.png

看到 ComponentSystem我们就可以知道里面的主要业务逻辑是基于Hybrid版ECS实现的,还是老套路,声明组件集合(产卵器),然后注入变量m_Group中

解析二
img_b2cd654878f84bc45201fe37e54f5ee5.png

在这一段代码块中我们可以看到,因为Length==1(一个产卵器),所以后进入到while循环中执行对应的业务逻辑,当然在最后Length会为0,后续会提到原因。会根据产卵的个数声明对应个数的 entities 数组。使用EntityManager.Instantiate实例化Cube,创建对应的position数组(个数等于cube创建个数)。使用EntityManager.Instantiate最明显的特点是创建的Cube在hierarchy视图中是没有的

img_c0e37115244391747a20308e476e3a11.gif
解析三
img_88751020e04b9702bc2f2629955c0cf6.png

使用GeneratePoints.RandomPointsOnCircle设置对应的随机位置(工程中有提供)。区分使用Local Position主要是这两地方,用EntityManager.AddComponentData把对应的父物体数据添加进去,类似于原来的 transform.SetParent。

img_b6dc2abb22a9ba42f6d43e26263d149e.png
LocalPosition中有数据
img_b08ced40b20fb3edbbb9a48f2b1304b2.png
LocalPosition中不含有数据
解析四
img_08a618e97635c52892f3cc6e1b3b8a85.png

这一部分也是使Length的值变为0的关键,把无用的数据entities与positions进行释放。移除对应的产卵器再重新注入。换句话说就是destory产卵器。


然后我们创建一个能让Cube自转的sysytem,类似于

img_c8b2a6f9745006418fb8e05d5e49245a.png

自转系统Code

using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Burst;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

public class RotationSpeedSystem : JobComponentSystem
{
    [BurstCompile]
    struct RotationSpeedRotation : IJobProcessComponentData<Rotation, RotationSpeed>
    {
        //Time.deltaTime
        public float dt;

        public void Execute(ref Rotation rotation, [ReadOnly]ref RotationSpeed speed)
        {
            rotation.Value = math.mul(math.normalize(rotation.Value), quaternion.axisAngle(math.up(), speed.Value * dt));
        }
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var job = new RotationSpeedRotation() { dt = Time.deltaTime };
        return job.Schedule(this, 64, inputDeps);
    }
}

解析一

在自转系统中我们没有指定对应的Group(组件系统集合),而且执行的Execute代码块所继承接口IJobParallelFor代替为IJobProcessComponentData,IJobProcessComponentData文档中的解释笔者并是不是很理解,但根据测试的结果笔者认为是使用ref关键字搜索全部的Rotation组件,然后把自身的RotationSpeed数值赋值进去。因为如果在Logo上添加Rotation与RotationSpeed组件,Logo物体也会进行旋转(赋值相关代码下面会有讲解)。

img_176619debc111e4e19bb185224766f7c.gif

触发Cube旋转系统

全部Code

using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Burst;
using Unity.Mathematics;
using Unity.Transforms;

//在RotationSpeedSystem前运行
[UpdateBefore(typeof(RotationSpeedSystem))]
public class RotationSpeedResetSphereSystem : JobComponentSystem
{
    /// <summary>
    /// Logo对应的entity group
    /// </summary>
    struct RotationSpeedResetSphereGroup
    {
        //Logo给予Cube速度对应的数据
        [ReadOnly] public ComponentDataArray<RotationSpeedResetSphere> rotationSpeedResetSpheres;
        //Logo对应的旋转半径
        [ReadOnly] public ComponentDataArray<Radius> spheres;
        //Logo对应的位置
        [ReadOnly] public ComponentDataArray<Position> positions;
        public readonly int Length;
    }
    //注入Logo组件集合
    [Inject] RotationSpeedResetSphereGroup m_RotationSpeedResetSphereGroup;

    /// <summary>
    /// 方块的entity group
    /// </summary>
    struct RotationSpeedGroup
    {
        //方块自身的旋转速度
        public ComponentDataArray<RotationSpeed> rotationSpeeds;
        //方块的位置
        [ReadOnly] public ComponentDataArray<Position> positions;
        //固定写法 数值等于Cube的个数
        public readonly int Length;
    }
    //注入Cube组件集合
    [Inject] RotationSpeedGroup m_RotationSpeedGroup;

    [BurstCompile]
    struct RotationSpeedResetSphereRotation : IJobParallelFor
    {
        /// <summary>
        /// 方块的速度
        /// </summary>
        public ComponentDataArray<RotationSpeed> rotationSpeeds;
        /// <summary>
        /// 方块的坐标
        /// </summary>
        [ReadOnly] public ComponentDataArray<Position> positions;

        //下面都是Logo上面的组件
        [ReadOnly] public ComponentDataArray<RotationSpeedResetSphere> rotationSpeedResetSpheres;
        [ReadOnly] public ComponentDataArray<Radius> spheres;
        [ReadOnly] public ComponentDataArray<Position> rotationSpeedResetSpherePositions;

        public void Execute(int i)//i 0-9  这个i值取对应 Schedule 中设置的 arrayLength 的数值 此Code中设置的为 m_RotationSpeedGroup.Length
        {
            //UnityEngine.Debug.Log($"长度{i}");
            //方块的中心点
            var center = positions[i].Value;

            for (int positionIndex = 0; positionIndex < rotationSpeedResetSpheres.Length; positionIndex++)
            {
                //计算圆球与方块的距离 ,小于指定具体传入速度
                if (math.distance(rotationSpeedResetSpherePositions[positionIndex].Value, center) < spheres[positionIndex].radius)
                {
                    rotationSpeeds[i] = new RotationSpeed
                    {
                        Value = rotationSpeedResetSpheres[positionIndex].speed
                    };
                }
            }
        }
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var rotationSpeedResetSphereRotationJob = new RotationSpeedResetSphereRotation
        {
            rotationSpeedResetSpheres = m_RotationSpeedResetSphereGroup.rotationSpeedResetSpheres,
            spheres = m_RotationSpeedResetSphereGroup.spheres,
            rotationSpeeds = m_RotationSpeedGroup.rotationSpeeds,
            rotationSpeedResetSpherePositions = m_RotationSpeedResetSphereGroup.positions,
            positions = m_RotationSpeedGroup.positions
        };

        return rotationSpeedResetSphereRotationJob.Schedule(m_RotationSpeedGroup.Length, 32, inputDeps);
    }
}

解析一

用的还是前面的老套路,与以往不同是在RotationSpeedResetSphereSystem上添加的[UpdateBefore(typeof(RotationSpeedSystem))]特性,他负责确保RotationSpeedResetSphereSystem在RotationSpeedSystem前执行,可以理解为手动的控制执行顺序


最后一步就是Cube速度衰减系统

全部Code

using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Burst;
using Unity.Mathematics;
using UnityEngine;

public class RotationAccelerationSystem : JobComponentSystem
{
    [BurstCompile]
    struct RotationSpeedAcceleration : IJobProcessComponentData<RotationSpeed, RotationAcceleration>
    {
        public float dt;
        //对Cube自身的RotationSpeed进行衰减处理
        public void Execute(ref RotationSpeed speed, [ReadOnly]ref RotationAcceleration acceleration)
        {
            speed.Value = math.max(0.0f, speed.Value + (acceleration.speed * dt));
        }
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var rotationSpeedAccelerationJob = new RotationSpeedAcceleration { dt = Time.deltaTime };
        return rotationSpeedAccelerationJob.Schedule(this, 64, inputDeps);
    }
}

解析一

使用的也是IJobProcessComponentData接口,整体和自旋转系统基本一致。

打完收工!!!真尼玛累~~~~

img_569463b7983f645f063dd7b1bef93e0c.png
相关实践学习
2分钟自动化部署人生模拟器
本场景将带你借助云效流水线Flow实现人生模拟器小游戏的自动化部署
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情:&nbsp;https://www.aliyun.com/product/ecs
相关文章
|
8天前
|
安全 编译器 Linux
深入解析与防范:基于缓冲区溢出的FTP服务器攻击及调用计算器示例
本文深入解析了利用缓冲区溢出漏洞对FTP服务器进行远程攻击的技术,通过分析FreeFlow FTP 1.75版本的漏洞,展示了如何通过构造过长的用户名触发缓冲区溢出并调用计算器(`calc.exe`)。文章详细介绍了攻击原理、关键代码组件及其实现步骤,并提出了有效的防范措施,如输入验证、编译器保护和安全编程语言的选择,以保障系统的安全性。环境搭建基于Windows XP SP3和Kali Linux,使用Metasploit Framework进行攻击演示。请注意,此内容仅用于教育和研究目的。
36 4
|
1月前
|
弹性计算 开发工具 git
2分钟在阿里云ECS控制台部署个人应用(图文示例)
作为一名程序员,我在部署托管于Github/Gitee的代码到阿里云ECS服务器时,经常遇到繁琐的手动配置问题。近期,阿里云ECS控制台推出了一键构建部署功能,简化了这一过程,支持Gitee和GitHub仓库,自动处理git、docker等安装配置,无需手动登录服务器执行命令,大大提升了部署效率。本文将详细介绍该功能的使用方法和适用场景。
2分钟在阿里云ECS控制台部署个人应用(图文示例)
|
1月前
|
存储 弹性计算 NoSQL
"从入门到实践,全方位解析云服务器ECS的秘密——手把手教你轻松驾驭阿里云的强大计算力!"
【10月更文挑战第23天】云服务器ECS(Elastic Compute Service)是阿里云提供的基础云计算服务,允许用户在云端租用和管理虚拟服务器。ECS具有弹性伸缩、按需付费、简单易用等特点,适用于网站托管、数据库部署、大数据分析等多种场景。本文介绍ECS的基本概念、使用场景及快速上手指南。
88 3
|
3月前
|
存储 弹性计算 缓存
阿里云服务器ECS通用型实例规格族特点、适用场景、指标数据解析
阿里云服务器ECS提供了多种通用型实例规格族,每种规格族都针对不同的计算需求、存储性能、网络吞吐量和安全特性进行了优化。以下是对存储增强通用型实例规格族g8ise、通用型实例规格族g8a、通用型实例规格族g8y、存储增强通用型实例规格族g7se、通用型实例规格族g7等所有通用型实例规格族的详细解析,包括它们的核心特点、适用场景、实例规格及具体指标数据,以供参考。
阿里云服务器ECS通用型实例规格族特点、适用场景、指标数据解析
|
2月前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
50 3
|
2月前
|
前端开发 JavaScript UED
axios取消请求CancelToken的原理解析及用法示例
axios取消请求CancelToken的原理解析及用法示例
167 0
|
3月前
|
弹性计算 运维 监控
阿里云ECS实例使用示例
使用阿里云ECS实例的流程简便快捷:登录阿里云控制台,在ECS实例列表中选择目标实例并进入详情页,点击“启动”按钮激活实例,确保预装系统和应用完成。运行后,通过控制台监控CPU、内存及磁盘使用情况,如需调整配置,可选择实例后点击“重启”应用新设置。阿里云ECS助力企业轻松上云、高效运维。[1][3] 相关链接:阿里云ECS使用流程 https://startup.aliyun.com/info/1078898.html
|
4月前
|
开发者 图形学 Java
揭秘Unity物理引擎核心技术:从刚体动力学到关节连接,全方位教你如何在虚拟世界中重现真实物理现象——含实战代码示例与详细解析
【8月更文挑战第31天】Unity物理引擎对于游戏开发至关重要,它能够模拟真实的物理效果,如刚体运动、碰撞检测及关节连接等。通过Rigidbody和Collider组件,开发者可以轻松实现物体间的互动与碰撞。本文通过具体代码示例介绍了如何使用Unity物理引擎实现物体运动、施加力、使用关节连接以及模拟弹簧效果等功能,帮助开发者提升游戏的真实感与沉浸感。
134 1
|
4月前
|
开发者 图形学 C#
揭秘游戏沉浸感的秘密武器:深度解析Unity中的音频设计技巧,从背景音乐到动态音效,全面提升你的游戏氛围艺术——附实战代码示例与应用场景指导
【8月更文挑战第31天】音频设计在游戏开发中至关重要,不仅能增强沉浸感,还能传递信息,构建氛围。Unity作为跨平台游戏引擎,提供了丰富的音频处理功能,助力开发者轻松实现复杂音效。本文将探讨如何利用Unity的音频设计提升游戏氛围,并通过具体示例代码展示实现过程。例如,在恐怖游戏中,阴森的背景音乐和突然的脚步声能增加紧张感;在休闲游戏中,轻快的旋律则让玩家感到愉悦。
133 0
|
4月前
|
安全 开发者 数据安全/隐私保护
Xamarin 的安全性考虑与最佳实践:从数据加密到网络防护,全面解析构建安全移动应用的六大核心技术要点与实战代码示例
【8月更文挑战第31天】Xamarin 的安全性考虑与最佳实践对于构建安全可靠的跨平台移动应用至关重要。本文探讨了 Xamarin 开发中的关键安全因素,如数据加密、网络通信安全、权限管理等,并提供了 AES 加密算法的代码示例。
73 0

推荐镜像

更多