Flutter学习-23-异步多线程结合

这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战

  • 我们之前学习了异步编程和dart中的多线程,接下来我们学习下异步多线程的结合

1. 异步中的多线程

先看一个例子,在异步中添加子线程,之后打印结果,打印结果是同步还是异步呢?

void main() {
  isoLoadDemo();
}

void isoLoadDemo(){

  Future(()=>compute(funcIso,1)).then((value) => print('1结束'));
  Future(()=>compute(funcIso,2)).then((value) => print('2结束'));
  Future(()=>compute(funcIso,3)).then((value) => print('3结束'));
  Future(()=>compute(funcIso,4)).then((value) => print('4结束'));
  Future(()=>compute(funcIso,5)).then((value) => print('5结束'));

}
funcIso(int num){

}
复制代码

打印顺序为异步

image.png

image.png

说明这个.then在子线程中执行了,我们修改下

void isoLoadDemo(){

  Future((){
    compute(funcIso,1);
  }).then((value) => print('1结束'));
  Future((){
    compute(funcIso,2);
  }).then((value) => print('2结束'));
  Future((){
    compute(funcIso,3);
  }).then((value) => print('3结束'));
  Future((){
    compute(funcIso,4);
  }).then((value) => print('4结束'));
  Future((){
    compute(funcIso,5);
  }).then((value) => print('5结束'));

}
复制代码

这个时候打印结果为:

image.png

说明按照添加的顺序同步,这里是因为这里我们把箭头函数 改为了函数。


void isoLoadDemo(){

  Future((){
   return compute(funcIso,1);
  }).then((value) => print('1结束'));
  Future((){
    return compute(funcIso,2);
  }).then((value) => print('2结束'));
  Future((){
    return compute(funcIso,3);
  }).then((value) => print('3结束'));
  Future((){
    return compute(funcIso,4);
  }).then((value) => print('4结束'));
  Future((){
    return compute(funcIso,5);
  }).then((value) => print('5结束'));

}
复制代码

我们添加了return,打印结果又是异步的了

image.png 我们看下compute是什么

image.png

ComputeImpl也是一个futureimage.png

  • 如果我们的异步返回的子线程的Future,那么我们.then执行的是子线程future的then
  • 如果我们不return,这个时候执行的是当前异步的.then.
void isoLoadDemo(){

  Future((){
   print('1');
   return compute(funcIso,1);
  }).then((value) => print('1结束'));
  Future((){
    print('2');
    return compute(funcIso,2);
  }).then((value) => print('2结束'));
  Future((){
    print('3');
    return compute(funcIso,3);
  }).then((value) => print('3结束'));
  Future((){
    print('4');
    return compute(funcIso,4);
  }).then((value) => print('4结束'));
  Future((){
    print('5');
    return compute(funcIso,5);
  }).then((value) => print('5结束'));

}
复制代码

我们看下异步任务执行的顺序是有序的还是无序的,打印结果:

image.png 说明异步任务执行的顺序是根据我们添加任务顺序进行执行的,我们修改下


void isoLoadDemo(){

  Future((){
   print('1');
    compute(funcIso,1);
  }).then((value) => print('1结束'));
  Future((){
    print('2');
  }).then((value) => print('2结束'));
  Future((){
    print('3');
     compute(funcIso,3);
  }).then((value) => print('3结束'));
  Future((){
    print('4');
     compute(funcIso,4);
  }).then((value) => print('4结束'));
  Future((){
    print('5');
     compute(funcIso,5);
  }).then((value) => print('5结束'));

}
复制代码

这个时候.then打印结果是同步还是异步呢?打印结果:

image.png 因为我们没有return 子线程的future,因此当前的.then执行的当前异步任务的then

2. 异步任务中微任务

我们看个例子

void taskDemo(){

  Future future = Future((){
    print('异步任务1');
    scheduleMicrotask((){
      print('微任务1');
    });
  });

  future.then((value) => print('微任务2'));

  future.whenComplete(() => print('微任务3'));
}
复制代码

我们知道.then和.whenComplete都是相当于微任务,因此他是在当前异步任务执行完成就会执行。

image.png

我们修改下.then.whenComplete的执行顺序,他们是按照添加的顺序执行的。


void taskDemo(){

  Future future = Future((){
    print('异步任务1');
    scheduleMicrotask((){
      print('微任务1');
    });
  });
  future.whenComplete(() => print('微任务3'));

  future.then((value) => print('微任务2'));

}
复制代码

image.png

3. Timer

我们定义一个Timer ,timer是一个异步任务,

void TimerDemo(){
  Timer.run(() {

    print('异步任务');
  });
  print('来了');
}
复制代码

执行结果:

image.png

那么timer是否会堵塞界面UI呢

@override void initState() {
  // TODO: implement initState
  super.initState();
  int count = 0;
  Timer.periodic(Duration(seconds: 1), (timer) {
    count++;
    print(count);
    if(count == 99){
      timer.cancel();
    }
  });
  }
复制代码

界面并没有卡住

image.png

这里有个问题,我们切换页面的时候如果状态没有保存,定时器没有销毁等于又建了一个定时器

image.png

我们这个时候就需要使用dispose,类似iOS中dealloc中销毁定时器,我们把timer定义外部变量,我们在页面销毁的是如果存在定时器并且定时器是在执行就销毁

@override
void dispose() {
  // TODO: implement dispose
  if( _timer!= null && _timer.isActive  )
    {
      _timer.cancel();
    }
  print('页面销毁了');
  super.dispose();

}
复制代码

image.png

我们添加个点击事件,进行循环,看下是否卡住UI

return GestureDetector(
  onTap: (){
    Future((){
      print('start');
      for(int i = 0;i<100000000000;i++){};
      print('end');
    });
    print('点击了');
  },
复制代码

卡住了,定时器都不执行了。 image.png 界面卡住了,所以我们真正耗时操作要放在子线程执行

Future((){
compute(func,123);
});

FutureOr func(message) {
  print('start');
  for(int i = 0;i<100000000000;i++){};
  print('end');
}

复制代码

可以点击,定时器也在执行。 image.png

猜你喜欢

转载自juejin.im/post/7033008830770479140