用了两年的flutter,有了一些心得,不虚头巴脑,只求实战有用,以供学习或使用flutter的小伙伴参考,学习尚浅,如有不正确的地方还望各路大神指正,以免误人子弟,在此拜谢~(原创不易,转发请标注来源和作者)
注意:无特殊说明,flutter版本为3.0+
Future 是Dart中常用的解决耗时操作的方案,一个async-await刚开始用的非常开心,但是后来发现了很多问题。在处理复杂业务逻辑的时候,页面请求非常多,耗时比较长,有时候UI开始变的卡顿,非常头疼。
我们知道Dart是单线程的异步模型,Future只是异步任务,依然会阻塞线程。那么我们知道不管是在Android还是IOS原生中,我们都有多线程的概念,充分利用手机CPU来处理事务。那么Dart是如何进行多线程的呢,那就是isolate。
一. isolate
Isolate是Dart对actor并发模式的实现,类似于 Android 中的 Thread 线程,但与 Thread 有本质的区别,Thread 可以实现内存共享,而 Isolate 不能。
运行中的Dart程序由一个或多个actor组成,这些actor也就是Dart概念里面的isolate。Isolate 可以方便的利用多核 CPU 来处理耗时操作,因内存不共享,需要通过 Port 进行消息通讯;其中 Port 消息传递也是异步的;
isolate 一般来解决耗时操作。
二.dio 的isolate改造
思路:将dio的基础信息,包括url,method,params,data等信息传入到isolate线程中去,然后将返回结果返回到住线程中。
我们直接看源码
class Resolve {
static Future<dynamic> resolve(String method, Map<String, dynamic> data) async {
ReceivePort receivePort = ReceivePort();
final Isolate isolate = await Isolate.spawn(
_entryPoint,
_Message(data['baseUrl'], data['path'], method, data['params'] ?? {}, data['data'],
receivePort.sendPort, data['headers']));
var result = await receivePort.first;
receivePort.close();
isolate.kill();
return result;
}
static void _entryPoint(_Message d) async {
try {
var res;
if (d.method == "get") {
res = await Http().get(d.path, baseUrl: d.baseUrl, params: d.params, headers: d.headers);
res = ApiResponse.fromJson(res);
}
if (d.method == "post") {
res = await Http().post(d.path, baseUrl: d.baseUrl, data: d.data, params: d.params, headers: d.headers);
res = ApiResponse.fromJson(res is Map ? res : jsonDecode(res));
}
Isolate.exit(d.sendPort, res);
} catch (e) {
Isolate.exit(d.sendPort);
}
}
}
不过发现一个问题,每一个请求都会开启一个线程,创建线程本身开销非常大,反复创建和销毁,非常容易造成资源浪费,甚至由于线程过多导致app崩溃,那如何解决呢?
三.LoadBalancer
我们先看下定义
/// A pool of runners, ordered by load.
///
/// Keeps a pool of runners,
/// and allows running function through the runner with the lowest current load.
///
/// The number of pool runner entries is fixed when the pool is created.
/// When the pool is [close]d, all runners are closed as well.
///
/// The load balancer is not reentrant.
/// Executing a [run] function should not *synchronously*
/// call methods on the load balancer.
class LoadBalancer implements Runner {
简单的来说可以理解为线程池,有多线程经验的同学知道,线程池解决的核心问题是资源管理问题,介绍了开销,合理配置cup和内存,性能和稳定性会更强,下面我们看下如何改造。
Future<LoadBalancer> loadBalancer = LoadBalancer.create(4, IsolateRunner.spawn);
class Resolve {
static Future<dynamic> resolve(String method, Map<String, dynamic> data) async {
final LoadBalancer lb = await loadBalancer;
var res = await lb.run<dynamic, _Message>(
_entryPoint,
_Message(
data['baseUrl'], data['path'], method, data['params'] ?? {}, data['data'] ?? {}, data['headers']));
return res;
}
}