推广

Flutter第十七章(Isolate 并发)

iseeyu3年前 (2024-02-22)推广117

模拟1.gif

可以看到点击计算按钮后很快就计算出了结果值,当然这是绝对理想的状态下。因为我们的计算并不复杂即使在主线程中计算也并未感知耗时的过程。那么现在将100 调整到 10000000000后来看下表现呢?

模拟2.gif

在修改计算值后再次点击计算按钮,整个应用是直接卡死掉了。在实际开发你的耗时操作可能不是这么一个计算,可能更多的是处理网络上的一些请求或处理结果等,然而类似的这样题应该是放到隔离器中去处理。

三、怎么创建 Isolate?

还是先回到源码中去,在源码中有这么一个派生函数:

      /**
       * Creates and spawns an isolate that shares the same code as the current
       * isolate.
       *
       * The argument [entryPoint] specifies the initial function to call
       * in the spawned isolate.
       * The entry-point function is invoked in the new isolate with [message]
       * as the only argument.
       *
       * The function must be a top-level function or a static method
       * that can be called with a single argument,
       * that is, a compile-time constant function value
       * which accepts at least one positional parameter
       * and has at most one required positional parameter.
       * The function may accept any number of optional parameters,
       * as long as it *can* be called with just a single argument.
       * The function must not be the value of a function expression
       * or an instance method tear-off.
       *
       * Usually the initial [message] contains a [SendPort] so
       * that the spawner and spawnee can communicate with each other.
       *
       * If the [paused] parameter is set to `true`,
       * the isolate will start up in a paused state,
       * just before calling the [entryPoint] function with the [message],
       * as if by an initial call of `isolate.pause(isolate.pauseCapability)`.
       * To resume the isolate, call `isolate.resume(isolate.pauseCapability)`.
       *
       * If the [errorsAreFatal], [onExit] and/or [onError] parameters are provided,
       * the isolate will act as if, respectively, [setErrorsFatal],
       * [addOnExitListener] and [addErrorListener] were called with the
       * corresponding parameter and was processed before the isolate starts
       * running.
       *
       * If [debugName] is provided, the spawned [Isolate] will be identifiable by
       * this name in debuggers and logging.
       *
       * If [errorsAreFatal] is omitted, the platform may choose a default behavior
       * or inherit the current isolate's behavior.
       *
       * You can also call the [setErrorsFatal], [addOnExitListener] and
       * [addErrorListener] methods on the returned isolate, but unless the
       * isolate was started as [paused], it may already have terminated
       * before those methods can complete.
       *
       * Returns a future which will complete with an [Isolate] instance if the
       * spawning succeeded. It will complete with an error otherwise.
       */
      external static Future<Isolate> spawn<T>(
          void entryPoint(T message), T message,
          {bool paused: false,
          bool errorsAreFatal,
          SendPort onExit,
          SendPort onError,
          @Since("2.3") String debugName});

参数作用:

①、entryPoint(必传): 传入的是一个函数,该函数指定要在派生的 isolate中调用的初始函数。这个函数必须是可以以单一参数调用的全局函数或静态方法,否则报错。

②、message(必传): 携带 SendPort的初始化消息,以便不同的 隔离区之间通信。

③、paused (非必传):如果指定pause为 true,则会在 message 调用 entryPoint函数之前将 isolate以暂停状态启动。如果需要恢复隔离器的状态使用
isolation.resume(isolation. pausecapability)即可。

④、errorsAreFatal(非必传):如果指定该参数为 true。则在 isolate中的 addOnExitListener 和 addErrorListener 监听事件中得到响应的退出和异常信息。

⑤、onExit、onError(配合 参数 ④一起使用)。

⑥、debugName(非必传),如果设置了该参数,在控制台相应的日字信息会通过该标识显示。

再次说明:其中 entryPoint 参数一定是一个静态函数或者全局函数,message 参数则是由 ReceivePort 创建的 SendPort,通过 receivePort.sendPort方式可以拿到。
下面来用get到的新技能将上面会卡死程序的计算改造下:
    import 'dart:isolate';

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_learn/page/dialog/LoadingViewDialog.dart';

    class IsolatePage extends StatefulWidget{

      @override
      State<StatefulWidget> createState() {
        return IsolatePageState();
      }
    }


    class IsolatePageState extends State<IsolatePage> {

      var content = "计算中...";


      static Future<dynamic> calculation(int n) async{

        //首先创建一个ReceivePort,因为创建isolate所需的参数,必须要有SendPort,SendPort需要ReceivePort来创建
        final response = new ReceivePort();
        //开始创建isolate,createIsolate是创建isolate必须要的参数。
        Isolate isolate = await Isolate.spawn(createIsolate,response.sendPort);

        //获取sendPort来发送数据
        final sendPort = await response.first as SendPort;
        //接收消息的ReceivePort
        final answer = new ReceivePort();
        //发送数据
        sendPort.send([n,answer.sendPort]);
        //获得数据并返回
        return answer.first;
      }

       //创建isolate必须要的参数
      static void createIsolate(SendPort initialReplyTo){
        final port = new ReceivePort();
        //绑定
        initialReplyTo.send(port.sendPort);
        //监听
        port.listen((message){
          //获取数据并解析
          final data = message[0] as num;
          final send = message[1] as SendPort;
          //返回结果
          send.send(sum(data));
        });

      }

      //计算0到 num 数值的总和
      static num sum(int num) {
        int count = 0;
        while (num > 0) {
          count = count+num;
          num--;
        }
        return count;
      }

      @override
      Widget build(BuildContext context) {


        return Scaffold(

          ///FloatingActionButton
          floatingActionButton: FloatingActionButton(
            elevation: 0,
            child: Text('计算'),
            onPressed: () {
              calculation(100000000).then((onValue){
                setState(() {
                  content = "总和$onValue";
                  print("计算结果:$onValue");
                });
              });
            },
          ),
          floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,

          appBar: AppBar(
            title: Text("Isolate"),
          ),

          body: SafeArea(
              child:Center(
                child: Column(
                  children: <Widget>[
                    Container(
                      width: double.infinity,
                      height: 400,
                      //前面章节中的自定义View
                      child: LoadingViewDialog(
                        dialogWidth: double.infinity,
                          //调用对话框
                        progress: CircularProgressIndicator(
                          strokeWidth: 3,
                          //背景颜色
                          backgroundColor: Colors.red,
                        ),

                        content: Text(
                          content,
                          style: TextStyle(color: Colors.blue),
                        ),
                        maxShowTime: 10000,
                      )
                    ),
                  ],
                ),
              ),
          ),
        );
      }
    }

运行效果:

Isolate模拟3.gif

可以看到再次点击计算按钮后,从加载圈圈就可以看出。整个程序照常运行,依然纵享湿滑。完美解决了上面的卡死现象。

四、Isolate的暂停,恢复,以及关闭

    //恢复 isolate 的使用
    isolate.resume(isolate.pauseCapability);

    //暂停 isolate 的使用
    isolate.pause(isolate.pauseCapability);

    //结束 isolate 的使用
    isolate.kill(priority: Isolate.immediate);

    //赋值为空 便于内存及时回收
    isolate = null;

你可能会问有没有更简单的方式啊? Isolate写起来好麻烦。确实是有的,由于Dart 中的Isolate确实比较重量级,因此Flutter为了简化用户代码,在foundation库中封装了一个轻量级compute操作,但其内部仍然还是 Isolate 在工作,只是 Flutter 在框架层帮我们做了简易优化。

五、compute 的使用

尽管compute在使用上很简单,也能处理耗时操作。但它的使用还是有很多限制的,它没有办法多次返回结果,也没有办法持续性的传值计算,每次调用,相当于新建一个隔离,如果调用过多的话反而会适得其反。这往往根据实际开发中业务情况来取决,如果只是单纯的处理几次耗时工作可以使用 compute,如果是需要一个任务来长时间的处理耗时类工作 则需要使用 Dart 中的 Isolate。

接下来使用 compute 简化上面的代码,修改 FloatingActionButton按钮 点击后使用 compute 方式来处理:

  ///FloatingActionButton
  floatingActionButton: FloatingActionButton(
    elevation: 0,
    child: Text('计算'),
    onPressed: () {

      compute(sum,100000000).then((onValue){
        setState(() {
          content = "总和$onValue";
          print("计算结果:$onValue");
        });
      });
    },
  ),

效果如下:

compute模拟4.gif

效果和直接使用 Isolate 处理一样,纵享湿滑 哈哈O(∩_∩)O

温馨提示: compute 所传入的函数和 Isolate 一样 必须是可以以单一参数调用的全局函数或静态方法,否则会报错。

本章节对 Isolate 的基本招式就打完了,更多高深秘法需要深入内部自行修炼了。

好了本章节到此结束,又到了说再见的时候了,如果你喜欢请留下你的小红星;你们的支持才是创作的动力,如有错误,请热心的你留言指正, 谢谢大家观看,下章再会 O(∩_∩)O

实例源码地址:https://github.com/zhengzaihong/flutter_learn/blob/master/lib/page/isolate/IsolatePage.dart

扫描二维码推送至手机访问。

版权声明:本文由西安泽虎代运营发布,如需转载请注明出处。

转载请注明出处https://www.0291.com.cn/post/56402.html

相关文章

我来分享什么是扁平化设计。

我来分享什么是扁平化设计。

设计 (Flat Design)这种简约的设计手法在近几年可说是常见的做法。 Flat Design 设计的UI元素,都是以以色块,排版间距来构建,如再搭配响应式网页设计(Responsive Web Design),用户在呈现页面上的带来相容于各尺寸的屏幕无差别体验,当然此款设计不仅单在网页资料...

教你承德网站建设在设计方面的特色体现在哪里。

教你承德网站建设在设计方面的特色体现在哪里。

近年来,随着的技术得到升级之后,可以说为客户进行建设网站的过程中,看出来在设计方面的特色也是越来越多的。每一个网站在布局的亮点和创意上不断增多,为的就是在网站运营的过程中会越来越火爆的。因此,在设计方面的特色体现在哪里呢?  网站页面中的版块和内容都进行自由设计和布局,为的就是让网站...

财富自由,不是做保险经纪人的终极目标

财富自由,不是做保险经纪人的终极目标

尹娜」总第321篇文章,2022年第68篇原创 这是我学到的7个关于的道理,是一个系列,本系列共7篇,本文是第六篇。 很多人抱着赚钱的想法来到这个行业,也有人宣传保险行业是个时间自由的行业,我转型之前也很看重这两点。现在从业两年多了,我赚到了以前在银行努...

淘宝开店借呗会关吗,美团开店宝在哪里关闭(店铺售假关店1年后又开)

淘宝开店借呗会关吗,美团开店宝在哪里关闭(店铺售假关店1年后又开)

支付宝花呗和借呗都是我们平时使用比较多的功能,帮助我们解决了很多经济上的困难。有些人使用支付宝实名账号去开通网店之后,发现账号里面的借呗功能不见了,...

做新闻营销,朝闻通新闻发稿机构有哪些方法?

  2022年4月17日,朝闻通新闻机构发表声明,声称再次推行白菜价格的公关服务,吸引所有公关公司和广告公司集体反对,认为朝闻通最好以利润为前提,先认识形势,利润至上。  朝闻通新闻发稿公司非常坚定,面对公关公司和广告公司的怀疑和指责,依旧坚持把企业新闻传播价格打下去,不禁...

销售技巧534:20个终端销售秘诀,100%提升店铺业绩!

销售技巧534:20个终端销售秘诀,100%提升店铺业绩!

1、掌握更多的商品回答不了商品方面问题的店员是失职。去找能够回答问题的店员,如果他又正好不在的话,顾客的心情会一落千丈,于是就换去其他店了,这直接影响到成交率!2、研究一下竞争对手的商品尽力给顾客提供最新的商品。在零售行业,店长亲自去附近的竞争店调查商品是理所当然的事。希望...

现在,非常期待与您的又一次邂逅

我们努力让每一部企业宣传片和抖音短视频成为商业大片