Unity跨平台原理
Project Setting -> Player -> Other Setting ->Scripting Backend
Mono:
Unity使用各种语言进行逻辑实现,在发布时会被编译成IL中间代码,最终这些中间代码在对应的操作系统上通过Mono VM虚拟机翻译成机器码来运行
IL2CPP:
在编译成IL中间代码过后,IL2CPP会将其转化成C++代码,再通过个平台的C++编译器直接编译成可执行的原生汇编代码。会将没有引用的类型自动裁剪掉
ThreadPool线程池
开发中频繁创建删除线程会带来性能消耗,产生内存垃圾,为避免这种开销,出现了ThreadPool
作用:
ThreadPool中有若干数量的线程,如果有任务需要处理时,会从线程池中获取一个空闲的线程来执行任务 任务执行完毕后线程不会销毁,而是被线程池回收以供后续任务使用 当线程池中所有的线程都在忙碌时,又有新任务要处理时,线程池才会新建一个线程来处理该任务, 如果线程数量达到设置的最大值,任务会排队,等待其他任务释放线程后再执行 线程池能减少线程的创建,节省开销,可以减少GC垃圾回收的触发
优缺点:
线程池相当于就是一个专门装线程的缓存池(Unity小框架套课中有对缓存池的详细讲解) 优点:节省开销,减少线程的创建,进而有效减少GC触发 缺点:不能控制线程池中线程的执行顺序,也不能获取线程池内线程取消 / 异常 / 完成的通知
相关API:
1.获取可用的工作线程数和I/O线程数
ThreadPool.GetAvailableThreads(out num1, out num2);
2.获取线程池中工作线程的最大/最小数目和I/O线程的最大数目
ThreadPool.GetMaxThreads(out num1, out num2);
3.设置线程池中可以同时处于活动状态的 工作线程的最大/最小数目和I / O线程的最大数目
大于次数的请求将保持排队状态,知直到线程池线程变为可用
更改成功返回true,失败返回false
ThreadPool.SetMaxThreads(20, 20)
4.将方法排入队列以便执行,当线程池中线程变得可用时执行
ThreadPool.QueueUserWorkItem((obj) => {print(obj); print(“开启了一个线程”); }, “123”);
其中第二参数的为obj的值
Task
Task的底层是线程Thread,它的创建遵循线程池的优点,提供了很多线程管理方法,可以更方便的让我们控制线程
创建无返回值Task的三种方式:
1.通过new一个Task对象传入委托函数并启动
Task t1 = new Task(() =>
{
int i = 0;
while (isRuning)
{
print("方式一:" + i);
++i;
Thread.Sleep(1000);
}
});
t1.Start();
2.通过Task中的Run静态方法传入委托函数
Task t2 = Task.Run(() =>
{
int i = 0;
while (isRuning)
{
print("方式二:" + i);
++i;
Thread.Sleep(1000);
}
});
3.通过Task.Factory中的StartNew静态方法传入委托函数
Task t3 = Task.Factory.StartNew(() =>
{
int i = 0;
while (isRuning)
{
print("方式三:" + i);
++i;
Thread.Sleep(1000);
}
});
创建有返回值Task:
只需在以上方法的基础上加上泛型即可,返回结果由t1.Result接收
注意此过程若t1线程未结束,则会阻塞主线程至线程结束返回值为止
同步执行Task:
t.RunSynchronously();
这里只能使用Task t = new Task(),因为另外两个会在初始化的时候就立即执行
使用后会阻塞主线程,直到该线程执行完毕
主动阻塞Task(任务阻塞)
1.Wait方法:等待任务执行完毕,再执行后面的内容 t2.Wait();
2.WaitAny静态方法:传入任务中任意一个任务结束就继续执行 Task.WaitAny(t1, t2);
3.WaitAll静态方法:任务列表中所有任务执行结束就继续执行 Task.WaitAll(t1, t2);
Task完成后继续其它Task(任务延续)
1.WhenAll静态方法 + ContinueWith方法:传入任务完毕后再执行某任务
Task.WhenAll(t1, t2).ContinueWith((t) =>
{
print("一个新的任务开始了");
int i = 0;
while (isRuning)
{
print(i);
++i;
Thread.Sleep(1000);
}
});
或 Task.Factory.ContinueWhenAll(new Task[] { t1, t2 },Func)
2.WhenAny静态方法 + ContinueWith方法:传入任务只要有一个执行完毕后再执行某任务
Task.WhenAny(t1, t2).ContinueWith(Func);
或 Task.Factory.ContinueWhenAny(new Task[] { t1, t2 }, Func)
异步方法async和await
异步并非多线程,甚至在单线程上都能完成,Unity的协程就是一种异步
async用于修饰函数
await写在async函数内部
使用async修饰异步方法 1.在异步方法中使用await关键字(不使用编译器会给出警告但不报错),否则异步方法会以同步方式执行 2.异步方法名称建议以Async结尾 3.异步方法的返回值只能是void、Task、Task<> 4.异步方法中不能声明使用ref或out关键字修饰的变量
当程序执行到await时,当前线程会立即释放,异步执行后面的任务,
若后面还有await,则主线程又会回归到当前函数直到遇到下一个await
示例
public async void CalcPathAsync(GameObject obj, Vector3 endPos)
{
print("开始处理寻路逻辑");
int value = 10;
await Task.Run(() =>
{
//处理复杂逻辑计算 我这是通过 休眠来模拟 计算的复杂性
Thread.Sleep(1000);
value = 50;
//是多线程 意味着我们不能在 多线程里 去访问 Unity主线程场景中的对象
//这样写会报错
//print(obj.transform.position);
});
print("寻路计算完毕 处理逻辑" + value);
obj.transform.position = Vector3.zero;
}
注意:Unity中大部分异步方法是不支持异步关键字async和await的,我们只有使用协同程序进行使用 虽然官方 不支持 但是 存在第三方的工具(插件)可以让Unity内部的一些异步加载的方法 支持 异步关键字 https://github.com/svermeulen/Unity3dAsyncAwaitUtil
静态导入 using static
例如:
Mathf.Max(a,b);
其中Max是Mathf中的静态方法
Mathf在UnityEngine命名空间中
using static UnityEngine.Mathf;
可以直接使用Max
异常筛选器when,nameof…….
字面值改进:int i = 1_9547_7895;下划线不影响程序
out新用法:Func(out int a,out int b);可以在参数里初始化(out相当于c++&引用传递)
弃元符号_:Func(out int a,out _);放弃第二个参数的传递
ref修饰临时变量和返回值:
ref用法回顾:
int a = 10;
ref int b = ref a; 引用传递
本地函数:函数内部的函数

评论(0)
暂无评论