美文网首页Flutter
Flutter入门之理解Isolate及compute

Flutter入门之理解Isolate及compute

作者: 秋分落叶 | 来源:发表于2019-08-23 09:58 被阅读0次

    一 . 原始代码

    为什么要Isolate,我们先看一段比较简单的代码:

    import 'package:flutter/material.dart';
    import 'package:flutter/foundation.dart';
     
    class TestWidget extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return TestWidgetState();
      }
    }
     
    class TestWidgetState extends State<TestWidget> {
      int _count = 0;
     
      @override
      Widget build(BuildContext context) {
        return Material(
          child: Center(
            child: Column(
              children: <Widget>[
                Container(
                  width: 100,
                  height: 100,
                  child: CircularProgressIndicator(),
                ),
                FlatButton(
                    onPressed: () async {
                      _count = countEven(1000000000);
                      setState(() {});
                    },
                    child: Text(
                      _count.toString(),
                    )),
              ],
              mainAxisSize: MainAxisSize.min,
            ),
          ),
        );
      }
     
      //计算偶数的个数
      static int countEven(int num) {
        int count = 0;
        while (num > 0) {
          if (num % 2 == 0) {
            count++;
          }
          num--;
        }
        return count;
      }
    }
    

    UI包含两个部分,一个不断转圈的progress指示器,一个按钮,当点击按钮的时候,找出比某个正整数n小的数的偶数的个数(请忽视具体算法,故意做耗时计算用,哈哈)。我们来运行一下代码看看效果:

    image

    二. 使用async优化

    那么有些同学就会说了,在dart中,有async关键字,我们可以用异步计算,这样就不会影响UI的刷新了,事实真的是这样吗?我们一起来修改一下代码:

    a. 将count改为asyncCountEven

      static Future<int> asyncCountEven(int num) async{
        int count = 0;
        while (num > 0) {
          if (num % 2 == 0) {
            count++;
          }
          num--;
        }
        return count;
      }
    

    b. 调用:
    _count = await asyncCountEven(1000000000);
    我们继续运行一下代码,看现象:

    image

    三. 使用compute优化

    那么我们怎么解决这个问题呢,其实很简单,我们知道卡顿的原因是在同一个线程中导致的,那我们有没有办法将计算移到新的线程中呢,当然是可以的。不过在dart中,这里不是称呼线程,是Isolate,直译叫做隔离,这么古怪的名字,是因为隔离不共享数据,每个隔离中的变量都是不同的,不能相互共享。

    但是由于dart中的Isolate比较重量级,UI线程和Isolate中的数据的传输比较复杂,因此flutter为了简化用户代码,在foundation库中封装了一个轻量级compute操作,我们先看看compute,然后再来看Isolate。

    要使用compute,必须注意的有两点,一是我们的compute中运行的函数,必须是顶级函数或者是static函数,二是compute传参,只能传递一个参数,返回值也只有一个,我们先看看本例中的compute优化吧:

    真的很简单,只用在使用的时候,放到compute函数中就行了。
    import 'package:flutter/foundation.dart';

    _count = await compute(countEven, 1000000000);
    再次运行,我们来看看效果吧:

    image

    可以看到,现在的计算并不会导致UI卡顿,完美解决问题。

    四. 使用Isolate优化

    但是,compute的使用还是有些限制,它没有办法多次返回结果,也没有办法持续性的传值计算,每次调用,相当于新建一个隔离,如果调用过多的话反而会适得其反。在某些业务下,我们可以使用compute,但是在另外一些业务下,我们只能使用dart提供的Isolate了,我们先看看Isolate在本例中的使用:

    a. 增加这两个函数

      static Future<dynamic> isolateCountEven(int num) async {
        final response = ReceivePort();
        await Isolate.spawn(countEvent2, response.sendPort);
        final sendPort = await response.first;
        final answer = ReceivePort();
        sendPort.send([answer.sendPort, num]);
        return answer.first;
      }
     
      static void countEvent2(SendPort port) {
        final rPort = ReceivePort();
        port.send(rPort.sendPort);
        rPort.listen((message) {
          final send = message[0] as SendPort;
          final n = message[1] as int;
          send.send(countEven(n));
        });
      }
    

    b. 使用

    _count = await isolateCountEven(1000000000);
    相对于compute复杂了很多,效果就不贴了,和compute一样,毫无卡顿。。

    五. 扩展

    isolate使用这么复杂,那么我们在那些情况下使用它呢?

    想象一下,假如你有一个业务,是使用socket和服务器连接,不断的从服务器中读取tcp流,如果业务需要拆分包的话,我们需要不断的将读取到的tcp流进行拆包分包,然后使用获取的数据来更新UI。首先,我们的socket与服务器通信,如果服务器推送消息过快,那么肯定会出现上面的情况,socket这边一直阻塞线程,导致UI刷新卡顿,所以我们需要将socket这边的业务放到隔离里面,但是,compute函数的限制我们也说了,它基本是是一次运行一次返回,但是业务要求是通过tcp的长连接不断获取服务器的数据,所以,这里我们就只能使用isolate,在UI和isolate里面使用ReceivePort进行双向通信,这样才能保证UI不卡顿的情况下仍然保持业务的完整性。

    原文链接:https://blog.csdn.net/email_jade/article/details/88941434

    相关文章

      网友评论

        本文标题:Flutter入门之理解Isolate及compute

        本文链接:https://www.haomeiwen.com/subject/pvczsctx.html