推广

Flutter第十七章(Isolate 并发)

iseeyu2年前 (2024-02-22)推广111

模拟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

相关文章

SEO优化的核心不是关键词排名,而是用户转化率的高低。

SEO优化的核心不是关键词排名,而是用户转化率的高低。

在SEO实践中,SEOER最常做的事情可能是批量生产内容和定期更新链接,这基本上是每个SEO人员经常做的事情,但也有一些容易被忽视的事情,比如内链、外链、关键词匹配、用户体验等,SEOER应该关注哪些细节?根据以往的经验,优化猩seo分析如下: 1、合理构建内链有利于搜索引擎快速识别...

如何排查网站收录异常解决网站收录异常的方法。

如何排查网站收录异常解决网站收录异常的方法。

在做SEO的过程中,百度的收录率起着至关重要的作用。如果网站出现异常表现,将直接影响到我们网站的后续优化和服务最终目标的能力。 一、什么是异常收录站点? 一般来说,相当于网站的异常情况,主要包括以下几个方面: (1)网站收录查询搜索结果大幅下降。 (2)百度收录多个索引。 (3)百度只收录...

企业蓝v、商品橱窗及抖音小店开通顺序

企业蓝v、商品橱窗及抖音小店开通顺序

很多人搞不清楚抖音上面的企业蓝v、商品橱窗、抖音小店他们的作用以及正正确开通顺序。 今天来帮大家体系化的梳理一下,重点是看完之后,可以帮你省很多钱。 ▌1.企业蓝v 企业蓝v是什么? 蓝v是企业号的认证,个体工商户、企业营业执照都可以认证蓝V。 如果是直接开通企业蓝v,需要6...

淘宝开店货源哪里找

淘宝开店货源哪里找

与厂家合作,如果自己的拿货量大,可以直接厂家拿货才能在价格上占有优势,而选择厂家也需要货比三家,因自己的拿货量大也有了可以和厂家讲价的底气。...

直通车高出价低溢价和低出价高溢价有何区别(直通车最高溢价是什么意思)

直通车高出价低溢价和低出价高溢价有何区别(直通车最高溢价是什么意思)

这两者之间本质区别是在于人群的相关性强弱,高出价低溢价的玩法适合人群相关性弱的产品,比如普通服装,产品没有太明显的人群特征,人群通用性高,这种产品主要的竞争力度是在关键词上,关键词适当的高价更有利于总体的曝光以及点击。...

新手必学的14种淘宝运营基本操作

新手必学的14种淘宝运营基本操作

一、淘宝货源 淘宝运营中自己家有货源是最好的,而我只能选择了阿里巴巴货源,一件代发的代理模式,基本筛选条件就是:诚信通会员,生产厂家认证,供应等级较高,商品进货价格低(在后期推广时大有优势),最后一点最重要就是不要代理费,这个模式也注定是店铺的软肋(发货问题,售后问题、纠纷退款问题,咱没什么话语权...

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

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