目录
前言
Task类是.NET平台上进行多线程和异步操作的重要工具。它提供了简洁而强大的API支持,使得开发者能够更加高效地利用系统资源,实现复杂的并行和异步操作。无论是在I/O密集型操作还是CPU密集型任务中,Task类都能为开发者提供有力的支持。
认识Task
命名空间:System.Threading.Tasks
类名:Task
Task顾名思义就是任务的意思
Task是在线程池基础上进行的改进,它拥有线程池的优点,同时解决了使用线程池不易控制的弊端。
它是基于线程池的优点对线程的封装,可以让我们更方便高效的进行多线程开发。
简单理解:
Task的本质是对线程Thread的封装,它的创建遵循线程池的优点,并且可以更方便的让我们控制线程。
一个Task对象就是一个线程。
创建无返回值Task的三种方式
第一种方式
通过new一个Task对象传入委托函数并启动
Task t1 = new Task(() =>
{
int i = 0;
while (isRuning)
{
print("方式一:" + i);
++i;
Thread.Sleep(1000);
}
});
t1.Start();
第二种方式
通过Task中的Run静态方法传入委托函数
Task t2 = Task.Run(() =>
{
int i = 0;
while (isRuning)
{
print("方式二:" + i);
++i;
Thread.Sleep(1000);
}
});
第三种方式
通过Task.Factory中的StartNew静态方法传入委托函数
Task t3 = Task.Factory.StartNew(() =>
{
int i = 0;
while (isRuning)
{
print("方式三:" + i);
++i;
Thread.Sleep(1000);
}
});
返回有返回值的Task
第一种方式
通过new一个Task对象闯入委托函数并启动
t1 = new Task<int>(() =>
{
int i = 0;
while (isRuning)
{
print("方式一:" + i);
++i;
Thread.Sleep(1000);
}
return 1;
});
t1.Start();
第二种方式
通过Task中的Run静态方法传入委托函数
t2 = Task.Run<string>(() =>
{
int i = 0;
while (isRuning)
{
print("方式二:" + i);
++i;
Thread.Sleep(1000);
}
return "1231";
});
第三种方式
通过Task.Factory中的StartNew静态方法传入委托函数
t3 = Task.Factory.StartNew<float>(() =>
{
int i = 0;
while (isRuning)
{
print("方式三:" + i);
++i;
Thread.Sleep(1000);
}
return 4.5f;
});
获取返回值
注意:
Resut获取结果时会阻塞线程
即如果task没有执行完成
会等待task执行完成获取到Result
然后再执行后边的代码,也就是说 执行到这句代码时 由于我们的Task中是死循环
所以主线程就会被卡死
同步执行Task
之前我们举的例子都是通过多线程异步执行的
如果希望Task能够同步执行
只需要调用Task对象中的RunSynchronously方法
注意:需要使用 new Task对象的方式,因为Run和StartNew在创建时就会启动
Task t = new Task(() =>
{
Thread.Sleep(1000);
print("这是一段话");
});
//t.Start();
t.RunSynchronously();
print("主线程执行");
不Start 而是 RunSynchronously
Task中线程阻塞的方式
1.Wait方法:等待任务执行完毕,再执行后面的内容
Task t1 = Task.Run(() =>
{
for (int i = 0; i < 5; i++)
{
print("t1:" + i);
}
});Task t2 = Task.Run(() =>
{
for (int i = 0; i < 20; i++)
{
print("t2:" + i);
}
});//t2.Wait();
2.WaitAny静态方法:传入任务中任意一个任务结束就继续执行
Task.WaitAny(t1, t2);
3.WaitAll静态方法:任务列表中所有任务执行结束就继续执行
Task.WaitAll(t1, t2);
Task完成后继续其它Task(任务延续)
1.WhenAll静态方法 + ContinueWith方法:传入任务完毕后再执行某任务
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
public class Test : MonoBehaviour
{
Task t1,t2;
bool isRuning =true;
void Start()
{
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 }, (t) =>
{
print("一个新的任务开始了");
int i = 0;
while (isRuning)
{
print(i);
++i;
Thread.Sleep(1000);
}
});
}
private void OnDestroy()
{
isRuning = false;
}
}
2.WhenAny静态方法 + ContinueWith方法:传入任务只要有一个执行完毕后再执行某任务
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
public class Test : MonoBehaviour
{
Task t1,t2;
bool isRuning =true;
void Start()
{
Task.WhenAny(t1, t2).ContinueWith((t) =>
{
print("一个新的任务开始了");
int i = 0;
while (isRuning)
{
print(i);
++i;
Thread.Sleep(1000);
}
});
Task.Factory.ContinueWhenAny(new Task[] { t1, t2 }, (t) =>
{
print("一个新的任务开始了");
int i = 0;
while (isRuning)
{
print(i);
++i;
Thread.Sleep(1000);
}
});
}
private void OnDestroy()
{
isRuning = false;
}
}
取消Task执行
方法一:通过加入bool标识 控制线程内死循环的结束
方法二:通过CancellationTokenSource取消标识源类 来控制
CancellationTokenSource对象可以达到延迟取消、取消回调等功能
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
public class Test : MonoBehaviour
{
Task t1,t2;
CancellationTokenSource c;
void Start()
{
c = new CancellationTokenSource();
//延迟取消
c.CancelAfter(5000);
//取消回调
c.Token.Register(() =>
{
print("任务取消了");
});
Task.Run(() =>
{
int i = 0;
while (!c.IsCancellationRequested)
{
print("计时:" + i);
++i;
Thread.Sleep(1000);
}
});
}
private void OnDestroy()
{
c.Cancel();
}
}
总结
1.Task类是基于Thread的封装
2.Task类可以有返回值,Thread没有返回值
3.Task类可以执行后续操作,Thread没有这个功能
4.Task可以更加方便的取消任务,Thread相对更加单一
5.Task具备ThreadPool线程池的优点,更节约性能