Dart中的异步和多线程(补充)

2022-03-28 09:03:09 浏览数 (1)

先来看个例子:

这个例子中,_testMethod里面有5个异步任务,每一个异步任务后面都跟有一个then。乍一看,我的结论是每个异步任务执行完毕之后就会紧接着执行该异步任务后面的then里面的任务,而每一个异步任务都是添加任务到子Isolate中(看着好像是这样,但其实并不是,后面会有说明),因此,then里面的打印任务应该是有顺序的。

好,分析完了之后,我们来看下执行结果:

通过结果我们发现,then里面的任务的执行并没有顺序,这是为什么呢?

为了说明上面的例子,我们再来看下另外一个例子:

在这个例子中,我没有使用箭头函数,而是直接采用标准的大括号写法。首先,在主线程中,我通过主Isolate中的Future添加了5个异步任务到主Isolate的eventQueue;接下来依次执行主Isolate的eventQueue中的异步任务,这里的异步任务就是添加_computeMethod中的任务到子Isolate中去,主Isolate中每一个异步任务执行完步之后都紧接着执行它的then里面的内容。因此,此处then里面的任务按异步任务的添加顺序依次执行没有任何的问题。

好,接下来对上例稍微改动一下:

可以看到,相对于上例,我就增加了个红框内的return,其他基本没变,然后执行结果就变成无序的了,为啥捏?

我们点进compute的源码看一下:

可以看到,compute函数最终也是返回一个Future。因此,此时的then对应的应该是compute函数最终返回的那个Future,该Future会将其内部包裹的任务添加到子Isolate的eventQueue中,而不再是最初的那个Future异步任务。所以这里的then是需要等待通过compute函数添加到子Isolate中的_computeMethod任务执行完毕之后才会紧接着执行,而子Isolate中的任务的执行是无序的,因此then中的任务执行也是无序的。

这里还有一点需要注意的是,虽然then对应的是compute函数返回的那个子Isolate中的Future,但是compute的then中的任务并不是在子Isolate中执行的,而是在主Isolate中执行的

好,现在我们回到最开始的那个例子,那个例子中,Future中的异步任务是通过箭头函数执行的。而如果你这一行代码是有返回值的,那么箭头函数是会默认给你加上return的,因此,如下两者是等同的:

这就解释了最初那个例子中的then里面的内容为啥打印是无序的了。

Timer简述

我们知道,在Flutter中可以通过Future来开启一个异步任务,接下来我们就看一下Future的源码:

代码语言:javascript复制
  factory Future(FutureOr<T> computation()) {
    _Future<T> result = new _Future<T>();
    Timer.run(() {
      try {
        result._complete(computation());
      } catch (e, s) {
        _completeWithErrorCallback(result, e, s);
      }
    });
    return result;
  }

可以看到,Future的底层就是通过Timer.run来实现的。也就是说,Timer.run就是开启的异步任务,接下来我们试一下:

代码语言:javascript复制
    Timer.run(() {
      print("111111");
    });
    print("222222");

打印结果如下:

代码语言:javascript复制
flutter: 222222
flutter: 111111

这也进一步印证了通过Timer.run开启的任务就是异步任务。

此时,我不禁想起一个iOS原生中的问题:

iOS中的Runloop有三种mode,UI事件是添加到优先级最高的UITrackingRunLoopMode模式下的,此时如果我们将timer事件添加到默认的NSDefaultRunLoopMode模式下,那么在在滑动UI的时候就会阻塞timer事件的执行。

关于该问题的详细描述,可参考我之前的文章:Runloop(上)。

对比到Flutter中,我在想,是不是在Flutter当中也会存在滑动列表的时候阻塞timer事件执行的问题。为了验证该问题,我首页列表页面的initState中开启一个定时器,如下:

然后,应用程序执行,我上下滑动首页面列表,发现控制台的打印不受到任何影响。这说明在Flutter中,UI事件不会阻塞Timer事件的执行

以上。

0 人点赞