Flutter隔离通信插件isolate_rpc的使用

Flutter隔离通信插件isolate_rpc的使用

isolate_rpcIsolate 的使用变得更加愉快。这是一个为 Isolate 设计的简单的RPC风格API。

特性

isolate_rpc 提供了一种更简单的方法来将非UI任务转移到隔离(Isolate),并且可以作为 Isolate.run(在 Flutter 中为 compute)的替代方案,并且性能更好,适用于 Dart SDK < 2.19.0。

该库显著减少了 Isolate.run 的开销。Isolate.run 每次调用都会创建新的隔离(Isolate)。在我的 M1 Pro MacBook 上进行基准测试,每个隔离启动的开销大约为 85 微秒。我相信在低端移动设备上这个数字会更大。

想象一下,如果你频繁地基于UI交互执行异步的后台操作,例如发送分析数据、获取远程API等,你可能希望消除这种开销。

查看基准结果

平台 支持情况
Flutter
Dart
Web fallback to use main thread

入门

步骤1:创建一个单个的RPC服务

import 'package:isolate_rpc/isolate_rpc.dart';

// 定义一个单个的RPC服务,即一个Isolate
IsolateRpc<int, int> rpc = IsolateRpc.single(
    processor: (data) => data + 1, // 执行逻辑,即加一操作
    debugName: "rpc" // 这将用于作为Isolate的名字
);

步骤2:执行请求并接收响应

// 在隔离中执行正常的Rpc请求
IsolateRpcResponse<int> resp = await rpc.execute(1);

print(resp.result); // 输出: 2

步骤3:关闭RPC服务

rpc.shutdown(); // 关闭接收端口和底层的Isolate。

高级用法

自定义请求和响应类型

class FooRequest {
  final String? someString;
  FooRequest([this.someString]);
}

class FooResponse {
  final int? someInt;
  FooResponse([this.someInt]);
}

IsolateRpc<FooRequest, FooResponse> rpc = IsolateRpc.single(
    processor: (fooRequest) {
      var str = fooRequest.someString;
      if (str == null) {
        throw ArgumentError("someString should not be null");
      } else {
        return FooResponse(int.parse(str));
      }
    },
    debugName: "rpc"
);

创建一个RPC服务池以提高性能

IsolateRpc<int, int> rpcPool = IsolateRpc.pool(
    size: 4, // 调整要启动的Isolate数量
    processor: (data) => data + 1,
    debugNamePrefix: "rpc-pool" // 内部使用 "rpc-pool-0", "rpc-pool-1", "rpc-pool-2", "rpc-pool-3"
);

使用 package:logging 日志记录器

import 'package:logging/logging.dart';

void main() {
  Logger.root.level = Level.FINEST;

  // 日志模式示例,用于与Isolate一起记录日志
  log.onRecord.listen((record) {
    print('${Isolate.current.debugName}: ${record.level.name}: ${record.time}: ${record.message}');
  });

  // 接收来自Rpc服务的所有日志
  var rpc = IsolateRpc.single(
      processor: (data) => data + 1,
      debugName: "rpc",
      logger: Logger("rpc_logger")
  );
}

获取更多详细信息,可以将Rpc服务转换为其基础类实例

var rpc = IsolateRpc.single(
    processor: (data) => data + 1,
    debugName: "rpc"
) as IsolateRpcService<int, int>;

print(rpc.id);
print(rpc.debugName);

var rpcPool = IsolateRpc.pool(
    size: 4,
    processor: (data) => data + 1,
    debugNamePrefix: "rpc-pool"
) as IsolateRpcExecutor<int, int>;

print(rpcPool.id);
print(rpcPool.debugName);
print(rpcPool.size);

性能对比(与 Isolate.run 对比)

查看基准实现

  • no_compute: 无工作负载,立即完成
  • compute: 大型JSON(数组包含300项)序列化和反序列化
  • communication: 发送长度从0到1GB的数据到Isolate并立即返回主进程

执行脚本

dart compile exe benchmark/main.dart -o ./benchmark/main
./benchmark/main

更多关于Flutter隔离通信插件isolate_rpc的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter隔离通信插件isolate_rpc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用isolate_rpc插件进行隔离通信的代码示例。isolate_rpc插件允许你在Flutter应用中通过隔离(isolate)执行耗时操作,从而避免阻塞UI线程。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加isolate_rpc依赖:

dependencies:
  flutter:
    sdk: flutter
  isolate_rpc: ^x.y.z  # 替换为最新版本号

然后运行flutter pub get来获取依赖。

2. 创建隔离通信服务

定义一个在隔离中执行的任务。例如,一个计算斐波那契数列的函数:

// lib/fibonacci_service.dart
import 'package:isolate_rpc/isolate_rpc.dart';

class FibonacciService implements RpcService {
  Future<int> fibonacci(int n) {
    if (n <= 1) return Future.value(n);
    return Future.value(fibonacci(n - 1) + fibonacci(n - 2));
  }

  @override
  RpcMethods getRpcMethods() {
    return RpcMethods(
      methods: {
        'fibonacci': fibonacci,
      },
    );
  }
}

3. 在UI中调用隔离服务

在你的主UI文件中,启动隔离服务并调用它:

// lib/main.dart
import 'package:flutter/material.dart';
import 'package:isolate_rpc/isolate_rpc.dart';
import 'fibonacci_service.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late RpcClient<FibonacciService> _rpcClient;
  int? _fibonacciResult;
  bool _isCalculating = false;

  @override
  void initState() {
    super.initState();
    _startRpcService();
  }

  void _startRpcService() async {
    _rpcClient = await RpcClient.start<FibonacciService>(
      isolateBuilder: () => FibonacciService(),
    );
  }

  void _calculateFibonacci(int n) async {
    setState(() {
      _isCalculating = true;
      _fibonacciResult = null;
    });

    try {
      final result = await _rpcClient.call('fibonacci', n);
      setState(() {
        _fibonacciResult = result;
        _isCalculating = false;
      });
    } catch (e) {
      print('Error calculating fibonacci: $e');
      setState(() {
        _isCalculating = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Isolate RPC Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextField(
                decoration: InputDecoration(
                  labelText: 'Enter number',
                ),
                keyboardType: TextInputType.number,
                onSubmitted: (value) {
                  final number = int.tryParse(value) ?? 0;
                  _calculateFibonacci(number);
                },
              ),
              SizedBox(height: 20),
              if (_isCalculating)
                CircularProgressIndicator()
              else if (_fibonacciResult != null)
                Text('Fibonacci(${_fibonacciResult!}) = $_fibonacciResult'),
            ],
          ),
        ),
      ),
    );
  }
}

4. 运行应用

现在你可以运行你的Flutter应用,并在输入框中输入一个数字来计算斐波那契数列。计算过程将在隔离中执行,因此不会阻塞UI线程。

总结

上述代码展示了如何在Flutter项目中使用isolate_rpc插件进行隔离通信。通过定义隔离中的服务和在UI中调用它,你可以执行耗时操作而不影响应用的响应性。

回到顶部