关于dart:flutter异步编程事件循环IsolateStream流

8次阅读

共计 4104 个字符,预计需要花费 11 分钟才能阅读完成。

事件循环、Isolate

开始前咱们须要明确 Dart 是单线程的并且 Flutter 依赖于 Dart

如果你晓得 js 中的 event loop 将很好了解 dart 的整个异步过程

先看一段代码


import 'dart:async';

Future eventLoop() async{print('A');

Future((){print('F');

scheduleMicrotask((){print('H');});

Future((){print('M');

}).then((_){print('N');

});

}).then((_){print('G');

});

Future((){print('I');

}).then((_){print('J');

});

scheduleMicrotask(text1);

scheduleMicrotask((){print('D');});

print('B');

}

void text1() {print('C');

scheduleMicrotask((){print('E');});

Future((){print('K');

}).then((_){print('L');

});

}

你只到输入后果吗

正确的输入程序是: A B C D E F G H I J K L M N

eventLoop

1、MicroTask 队列

微工作队列,个别应用 scheduleMicroTask 办法向队列中增加

这是大多数时候你不用应用的货色。比方,在整个 Flutter 源代码中 scheduleMicroTask() 办法仅被援用了 7 次,所以最好优先思考应用 Event 队列

2、Event 队列

I/O、手势、绘图、计时器、流、futures 等等 异步操作都将进入 event 队列

尽量应用事件队列能够使微工作队列更短,升高事件队列卡死的可能性

代码执行程序

首先咱们晓得 dart 是单线程的,所以 dart 的代码执行程序是:

  1. 同步代码顺次执行
  2. 碰到异步代码先进对应的队列中,而后继续执行上面的代码
  3. 当同步代码执行结束,先去看 MicroTask 队列中的工作,将 MicroTask 队列中的工作顺次执行结束
  4. MicroTask 中的工作执行结束后,再去看 Event 队列中的工作,event 队列出一个工作 而后执行,而后回到第三步 循环 直到所有队列都清空

Isolate

Isolate 是 Dart 中的 线程,Flutter 的代码都是默认跑在 root isolate 上的

「Isolate」在 Flutter 中并不共享内存。不同「Isolate」之间通过「音讯」进行通信。


import 'dart:async';

import 'dart:io';

import 'dart:isolate';

import 'package:flutter/foundation.dart';

import 'package:flutter/material.dart';

// 一个普普通通的 Flutter 利用的入口

//main 函数这里有 async 关键字,是因为创立的 isolate 是异步的

void main() async{runApp(MyApp());

//asyncFibonacci 函数里会创立一个 isolate,并返回运行后果

print(await asyncFibonacci(20));

}

// 这里以计算斐波那契数列为例,返回的值是 Future,因为是异步的

Future<dynamic> asyncFibonacci(int n) async{

// 首先创立一个 ReceivePort,为什么要创立这个?// 因为创立 isolate 所需的参数,必须要有 SendPort,SendPort 须要 ReceivePort 来创立

final response = new ReceivePort();

// 开始创立 isolate,Isolate.spawn 函数是 isolate.dart 里的代码,_isolate 是咱们本人实现的函数

//_isolate 是创立 isolate 必须要的参数。await Isolate.spawn(_isolate,response.sendPort);

// 获取 sendPort 来发送数据

final sendPort = await response.first as SendPort;

// 接管音讯的 ReceivePort

final answer = new ReceivePort();

// 发送数据

sendPort.send([n,answer.sendPort]);

// 取得数据并返回

return answer.first;

}

// 创立 isolate 必须要的参数

void _isolate(SendPort initialReplyTo){final port = new ReceivePort();

// 绑定

initialReplyTo.send(port.sendPort);

// 监听

port.listen((message){

// 获取数据并解析

final data = message[0] as int;

final send = message[1] as SendPort;

// 返回后果

send.send(syncFibonacci(data));

});

}

int syncFibonacci(int n){return n < 2 ? n : syncFibonacci(n-2) + syncFibonacci(n-1);

}

因为 Root isolate 会负责渲染,还有 UI 交互,如果咱们有一个很耗时的操作呢?后面晓得 isolate 里是一个 event loop(事件循环),如果一个很耗时的 task 始终在运行,那么前面的 UI 操作都被阻塞了,所以如果咱们有耗时的操作,就应该放在 isolate 里!

Stream(流)

什么是流?

  • 这个大机器就是 StreamController,它是创立流的形式之一。
  • StreamController 有一个入口,叫做 sink
  • sink 能够应用 add 办法放货色进来,放进去当前就不再关怀了。
  • 当有货色从 sink 进来当前,咱们的机器就开始工作
  • StreamController 有一个进口,叫做 stream
  • 机器处理完毕后就会把产品从进口丢进去,然而咱们并不知道什么时候会进去,所以咱们须要应用 listen 办法始终监听这个进口
  • 而且当多个物品被放进来了之后,它不会打乱程序,而是先入先出

应用 Stream


StreamController controller = StreamController();

// 监听这个流的进口,当有 data 流出时,打印这个 data

StreamSubscription subscription =

controller.stream.listen((data)=>print("$data"));

controller.sink.add(123);

// 输入:123

你须要将一个办法交给 stream 的 listen 函数,这个办法入参 (data) 是咱们的 StreamController 处理完毕后产生的后果,咱们监听进口,并取得了这个后果(data)。这里能够应用 lambda 表达式,也能够是其余任何函数

transform

如果你须要更多的管制转换,那么请应用 transform()办法。他须要配合 StreamTransformer 进行应用。


StreamController<int> controller = StreamController<int>();

final transformer = StreamTransformer<int,String>.fromHandlers(handleData:(value, sink){if(value==100){sink.add("你猜对了");

}

else{sink.addError('还没猜中,再试一次吧');

}

});

controller.stream

.transform(transformer)

.listen((data) => print(data),

onError:(err) => print(err));

controller.sink.add(23);

//controller.sink.add(100);

// 输入:还没猜中,再试一次吧

StreamTransformer<S,T> 是咱们 stream 的检查员,他负责接管 stream 通过的信息,而后进行解决返回一条新的流。

  • S 代表之前的流的输出类型,咱们这里是输出一个数字,所以是 int。
  • T 代表转化后流的输出类型,咱们这里 add 进去的是一串字符串,所以是 String。
  • handleData 接管一个 value 并创立一条新的流并裸露 sink,咱们能够在这里对流进行转化

Stream 的品种

  • “Single-subscription” streams 单订阅流
  • “broadcast” streams 多订阅流

单订阅流


StreamController controller = StreamController();

controller.stream.listen((data)=> print(data));

controller.stream.listen((data)=> print(data));

controller.sink.add(123);

// 输入: Bad state: Stream has already been listened to. 单订阅流不能有多个收听者。

单个订阅流在流的整个生命周期内仅容许有一个 listener

多订阅流


StreamController controller = StreamController();

// 将单订阅流转化为播送流

Stream stream = controller.stream.asBroadcastStream();

stream.listen((data)=> print(data));

stream.listen((data)=> print(data));

controller.sink.add(123);

// 输入:123 123

播送流容许任意数量的收听者,且无论是否有收听者,他都能产生事件。所以中途进来的收听者将不会收到之前的音讯。

参考深刻理解 isolate
永恒原文地址 flutter 异步编程

正文完
 0