在之前的文章中,我们已经学习了Future异步编程和Isolate多线程的使用,今天我们来看一下,如何使用异步编程与多线程结合使用;
异步与多线程结合使用
我们先来看一段代码:
void main() {testIsoLoad();}void testIsoLoad() {Future(() => compute(func, 123)).then((value) => print('1'));Future(() => compute(func, 123)).then((value) => print('2'));Future(() => compute(func, 123)).then((value) => print('3'));Future(() => compute(func, 123)).then((value) => print('4'));Future(() => compute(func, 123)).then((value) => print('5'));}func(int message) {}
运行工程,查看打印结果:
从打印结果我们可以得到结论,这几个print操作时异步的,他是在子线程处理的;
但是按照我们之前对Future的研究,多个Future之间应该是同步的才对,那么为什么此处却变成了异步的呢?接下来,我们在其他代码保持不变的情况下,将testIsoLoad方法中的代码进行如下修改:

然后,我们运行工程,看到一下打印结果:

警告我们多次运行项目,最后发现打印顺序都是1、2、3、4、5,那么这是为什么呢?怎么又变成了同步的呢?我们仅仅只是将=>的调用方式换成了{},怎么代码的执行结果就不一样了呢?
需要注意的是,=>在调用的过程中,有将执行结果进行return操作的含义,也就是说=> compute(func, 123)的执行,会将compute(func, 123)的结果进行return操作,我们来验证一下,将testIsoLoad方法修改如下:

运行结果如下:

多次运行之后,发现结果并不是固定的,也就是说,我们进行了return操作之后,同步的执行流程变成了异步的,这也验证了我们上边所说的=>函数的调用方式会将结果进行return操作;
如果在Future中return了子线程的Future(compute是对Future的封装),那么其then将会处理子线程的异步任务;那么既然then是子线程的异步操作了,那么Future中的任务是什么情况呢?
我们在Future中添加如下打印:

运行结果;

可以看到,虽然then处理的是子线程的异步任务,但是Future中依然还是同步任务;
Future与微任务
我们来看下边这样代码:
Future f = Future(() {print('异步任务1');scheduleMicrotask(() {print('微任务1');});});
很明显,我们都能才到执行结果是:异步任务先执行,然后执行微任务;

如果,我们继续给f添加一个then方法呢?
Future f = Future(() {print('异步任务1');scheduleMicrotask(() {print('微任务1');});});f.then((value) {print('微任务2');});
此时的执行结果如何呢?

结果是微任务2比微任务1先执行,这是因为then方法我们可以看做和Future的任务是一个整体,也就是then方法(一个微任务)先添加进入队列,然后微任务1的微任务会添加到then方法后边,所以then方法先执行;
不仅仅如此,我们再添加一个whenComplete方法查看打印结果:
Future f = Future(() {print('异步任务1');scheduleMicrotask(() {print('微任务1');});});f.whenComplete(() {print('完成');});f.then((value) {print('微任务2');});
打印结果如下:

whenComplete也可以看做和Future的任务是一个整体,whenComplete和then会按照添加顺序执行;
异步与多线程的选择
那么究竟什么时候使用异步任务,什么时候使用多线程操作呢?
虽然Future是个异步任务,但是在Future中的耗时操作是会阻塞主线程的。看如下代码:

我们在相机按钮的点击方法中添加了一个for循环来模拟耗时操作,可以从打印结果看到,当Future中的耗时操作开始执行之后,界面被阻塞,无法滑动!当耗时操作结束之后,才能进行滑动操作;
这个时候,我们可以使用compute来操作:
将耗时操作放在compute的方法中,将不会阻塞主线程,此处可以直接使用compute,不用Future;
