首页 > Python基础教程 >
-
C#教程之[多线程] Thread
多线程
概述
单任务处理:一个任务完成后才能进行下一个任务。
多任务处理:CPU分时操作,每个任务看似同时运行。
进程
应用程序的一个运行实例,包含程序所需资源的内存区域,是操作系统进行资源分配的单元,进程隔离了正在执行的不同程序。(打开某一个软件,分配CPU,隔离其他软件)
优点:进程间相互独立,互不影响。
线程
进程中的一个执行单元(进程是程序边界,要靠线程执行程序,线程指向方法,执行完毕释放线程),是CPU分配时间片的单位,一个进程可以包含多个线程,且相互独立,共享当前进程所有资源。
优点:
- 并发执行,合理使用CPU资源。
- 相同程序的线程共享堆内存。
缺点:
- 频繁创建/销毁线程增加性能开销。
- 访问共享资源可能造成冲突。
- 辅助线程不能访问Unity API。
注意事项:
- Unity的API不能在辅助线程运行。
- Unity定义的基本结构(int,Vector3,Quaternion等)可以在辅助线程计算。
- Unity定义的基本类型的函数可以在分线程运行。
多线程
在单核系统的一个单位时间内,CPU只能运行单个线程,运行顺序取决于线程的优先级。如果在单位时间内线程未能完成执行,系统就会把线程的状态信息保存到线程的本地存储器(TLS) 中,以便下次执行时恢复执行。因为切换频密,所以多线程可被视作同时运行,而实际只是一个假象。
在多核系统的一个单位时间内,进程或线程可以在不同的CPU中运行,使得真正的并行处理。
适用性
耗时的任务,通过多线程可以并行处理。
一个程序完成多个任务,通过多个线程使用多核CPU来处理,可以提升性能。
多线程实现
命名空间:System.Threading;
Thread
- 创建线程: 创建Thread类的一个对象,分配一个线程工作方法 。
Thread thread = new Thread(工作方法);
- 启动线程:Start方法。
thread.Start();
- 终止线程:工作方法自然退出、线程终止。
thread. Abort ();
ThreadPool
在频繁创建和销毁线程时使用线程池技术,可以有效减少时间以及系统资源的开销。
ThreadPool.QueueUserWorkItem(工作方法);
前/后台线程
前台线程:程序必须等待所有前台线程结束后才能退出。(只要有一个前台线程未退出,进程就不会终止!即说的就是程序不会关闭!)[Thread创建的线程默认前台线程]
后台线程:程序不考虑后台线程,后台线程随程序退出而结束。[ThreadPool创建的线程默认后台线程]
备注:Unity程序退出后,前台线程也随即关闭。
新建的子线程可以是前台线程或者后台线程,前台线程必须全部执行完,即使主线程关闭掉,这时进程仍然存活。
线程状态
未启动状态 Unstarted:创建线程对象。
运行状态Running:执行绑定的方法。
等待睡眠阻塞状态 WaitSleepJoin:暂时停止执行,资源交给其他线程使用。
终止状态 Stopped:线程销毁。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using UnityEngine.UI; using System.Threading; public class ThreadDemo : MonoBehaviour { private int second = 60; private Text text; private void Start() { text = GetComponent<Text>(); Thread thread = new Thread(Timer); thread.Start(); } private void Update() { if (action!=null) { action(); action = null; } } private void Timer() { while (second>0) { Thread.Sleep(1000);//睡一会 期间没有CPU的调度 action = () => { second--; text.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60); }; } } private Action action; }
线程同步
需要同步的原因:
多个线程同一时刻访问共享资源(线程共享实例变量,静态变量),由于每个线程都不知道其他线程的操作,结果将产生不可预知的数据损坏。
同步:
线程之间相互等待排队执行。
如何同步:
将需要同步的代码用关键字lock锁定,锁定后该代码对于线程来讲就是独占使用的。当其他线程试图进入被锁定的临界区时,只能等待解锁后才可访问。因此锁定代码时是排队访问的,所以叫线程同步。
Lock锁原理:
对象在堆中的分配:实例成员、同步块索引 (默认索引-1)、类型指针(指向类型对象)。
对象上锁后,同步索引块会指向同步块数组中的一个对象。
当其他对象执行lock的时候会等待该对象同步索引设置为-1。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Threading; public class Bank { public static int Money = 1; public static object o = new object(); //必须使用引用类型 //优先使用object public static void Get(int val) { lock (o)//-1 0 只有是-1的时候 锁打开 否则锁关闭 { //同步块索引 类型对象指针 //共享读 独占写 //枷锁(对象) 流程 if (Money >= val) { //线程冲突 0 -1 -2 如何解决???加锁 Thread.Sleep(1000); Money -= val; Debug.Log("取钱成功!余额:" + Money); } else { Debug.Log("取钱失败!余额:" + Money); } //线程离开代码块 索引块 设置为-1 } } } public class ThreadDemo2 : MonoBehaviour { private void Start() { //Bank.Get(1); //同步调用 排队 ThreadPool.QueueUserWorkItem(o => { Bank.Get(1); }); ////线程调用(多线程) 不排队 } }