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

事件循环、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异步编程

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理