「这是我参加11月更文应战的第23天,活动概况检查:2021最后一次更文应战」

咱们在之前的文章中已经讲解了怎么运用FuturescheduleMicrotask,可是咱们发现,这两个都是同步的,其履行次序都是能够确认的。接下来咱们介绍Dart中的异步多线程操作;

Isolate

咱们先来看一段代码履行的成果:

void testIsolate() {
  print('1');
  Future(() => print('3'));
  sleep(const Duration(seconds: 2));
  print('2');
}

咱们根据之前的学习,能够知道打印成果是1、2、3,咱们看一下打印成果:

Flutter(二十五)-Dart中多线程Isolate

根据打印成果,也的确验证了咱们的定论;可是很明显,即便咱们阻塞了主线程,Future里边的使命仍然没有先履行;那么有没有办法能够在主线程阻塞的时分,让3先打印出来呢?这个时分就需求用到Flutter中的多线程操作Isolate了;

咱们将代码修正如下:

void testIsolate() {
  print('1');
  Isolate.spawn(func, 10);
  sleep(const Duration(seconds: 2));
  print('2');
}
func (int count) => print('3');

此刻,咱们来看一下打印成果:

Flutter(二十五)-Dart中多线程Isolate

能够看到,咱们阻塞了主线程,即便2没有第一时间打印出来,可是不影响3的输出,也便是Isolate没有因为主线程的阻塞,而拖延调用;那么Isolate是否真实子线程呢?

为了验证Isolate是否在子线程,咱们将代码修正如下:

void testIsolate() {
  print('1');
  Isolate.spawn(func, 10);
  Isolate.spawn(func2, 10);
  Isolate.spawn(func, 10);
  Isolate.spawn(func2, 10);
  Isolate.spawn(func, 10);
  Isolate.spawn(func2, 10);
  sleep(const Duration(seconds: 2));
  print('2');
}
func (int count) {
  print('第一个');
}
func2 (int count) {
  print('第二个');
}

履行成果:

Flutter(二十五)-Dart中多线程Isolate

能够看到打印次序不再是固定的了,变成了随机的,证明了Isolate的确是在子线程;

Isolate的独立内存空间

需求留意的是,Dart中的多线程不仅仅是拓荒了一条’线程‘,此处的Isolate与其说是线程,不如说他更像一个进程,因为Isolate有独立的内存空间(主要是自己创立的对象/数据);这就意味着,每一个Isolate之间的数据是独立的,不会存在资源争夺的问题,也就不需求运用进行操作,那么咱们访问数据的时分,也就不能直接访问;

咱们来看一段代码:

void testIsolate() {
  print('1');
  Isolate.spawn(func, 100);
  sleep(const Duration(seconds: 2));
  print('a = $a');
  print('2');
}
int a = 10;
func (int count) {
  a = count;
  print('func 中 a: $a');
}

在这段代码中,咱们定义了一个变量a,默认值为10,然后在func办法中奖count值赋值给a,然后在Isolate中,咱们将给func办法传值为100,那么按照正常的逻辑,咱们在主线程阻塞2秒之后的打印成果应该是a = 100,那么是不是这样呢?咱们来看一下打印成果:

Flutter(二十五)-Dart中多线程Isolate

咱们看到,即便咱们在func办法中,给a赋值为100,可是在之后的打印中a仍是10,这也就意味着Isolate中的资源是不能被争夺的,它是独立的;

获取Isolate中被修正的数据

可是,咱们的确在某些时分,需求在子线程中去修正a的值,那么咱们应该如何操作呢?咱们将代码修正如下:

void testIsolate() {
  print('1');
  // 创立一个接口port
  ReceivePort port = ReceivePort();
  // 创立一个Isolate
  Isolate.spawn(func, port.sendPort);
  // 经过port监听数据的改变
  port.listen((message) {
    a = message;
    print('port中监听到 a = $a');
  });
  sleep(const Duration(seconds: 2));
  print('a = $a');
  print('2');
}
int a = 10;
func (SendPort sendPort) {
  sendPort.send(100);
  print('func 中 a: $a');
}

此刻,咱们再次来检查运行成果:

Flutter(二十五)-Dart中多线程Isolate

咱们看到,此刻咱们能够监听到a被修正了;

在这个过程中,咱们做了四件事:

  • 创立一个接口:ReceivePort;
  • 创立一个Isolate;
  • 运用创立的ReceivePort来监听数据的改变;
  • Isolate关联的办法中运用SendPort发送音讯进行传值;

经过以上四步操作,咱们能够修正Isolate内部的数据,并获取到新值;

可是需求留意的是,咱们运用这种方式开监听数据的时分,相当于拓荒了空间,那么就需求咱们自己来办理毁掉;最终代码如下:

void testIsolate() async {
  print('1');
  // 创立一个接口port
  ReceivePort port = ReceivePort();
  // 创立一个isolate
  Isolate isolate =  await Isolate.spawn(func, port.sendPort);
  // 经过port监听数据的改变
  port.listen((message) {
    a = message;
    print('port中监听到 a = $a');
    // 关闭port
    port.close();
    // 毁掉 isolate
    isolate.kill();
  });
  sleep(const Duration(seconds: 2));
  print('a = $a');
  print('2');
}
int a = 10;
func (SendPort sendPort) {
  sendPort.send(100);
  print('func 中 a: $a');
}

咱们需求将ReceivePort关闭掉,将Isolate进行毁掉;

需求留意的是,Isolate是多线程操作,所以此处的await并不会让后续代码发生类似Future的等待作用;

compute

Flutter中的多线程除了Isolate之外,还有一个compute,它是对Isolate的封装;咱们来看一段代码:

Flutter(二十五)-Dart中多线程Isolate

咱们来看这段代码的履行作用:

Flutter(二十五)-Dart中多线程Isolate

从履行作用咱们能够确认,compute也是在子线程履行的;

可是computeIsolate是有区别的,compute能够接纳使命func中的回来值的;咱们将代码修正如下:

Flutter(二十五)-Dart中多线程Isolate

检查运行成果:

Flutter(二十五)-Dart中多线程Isolate

能够看到咱们接纳到了func办法的回来值;

需求留意的是,computeawait会引起和Future中同样的等待作用;

那么compute是否是数据阻隔呢?

咱们对代码进行如下修正:

Flutter(二十五)-Dart中多线程Isolate

运行成果:

Flutter(二十五)-Dart中多线程Isolate

能够看到compute能够接纳使命的回来数据,可是在使命内部针对全局变量a的修正,在外部仍然无法获取;