MST

星途 面试题库

面试题:Flutter 异步/await 优化性能之深入探究与实践

在高并发的Flutter应用场景下,如同时发起大量网络请求,使用异步/await可能会遇到资源竞争、内存泄漏等问题。请阐述如何通过合理使用异步/await以及相关机制(如Future队列、Stream等)来解决这些问题,提升应用的稳定性和性能,并给出详细的解决方案与代码示例。
49.7万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

1. 资源竞争问题

在高并发场景下,资源竞争通常发生在多个异步任务同时访问和修改共享资源时。

  • 解决方案
    • 使用锁机制:在Dart中,可以使用Lock类来实现简单的锁机制。当一个异步任务获取到锁后,其他任务必须等待锁被释放才能访问共享资源。
    • 隔离共享资源:尽量减少共享资源的使用,将数据按任务或模块进行隔离,避免多个任务同时操作同一数据。
  • 代码示例
import 'dart:async';
import 'dart:io';

class Resource {
  int data = 0;
}

class ResourceManager {
  final _lock = Lock();
  final Resource _resource = Resource();

  Future<int> readData() async {
    await _lock.synchronized(() async {
      return _resource.data;
    });
  }

  Future<void> writeData(int value) async {
    await _lock.synchronized(() async {
      _resource.data = value;
    });
  }
}

2. 内存泄漏问题

内存泄漏在高并发异步任务中,可能由于任务持有对不再需要的对象的引用,导致垃圾回收器无法回收这些对象。

  • 解决方案
    • 及时释放资源:确保在异步任务完成后,及时释放所有不再需要的资源,如关闭网络连接、释放文件句柄等。
    • 取消未完成任务:当不再需要某个异步任务时,能够取消它,避免任务继续执行并占用资源。在Flutter中,Future可以通过CancelToken来实现取消操作。
  • 代码示例
import 'dart:async';
import 'package:http/http.dart' as http;

void main() async {
  final cancelToken = CancelToken();
  try {
    final response = await http.get(Uri.parse('https://example.com'),
        headers: {'Cancel-Token': cancelToken.token});
    print(response.body);
  } on IOException catch (e) {
    if (e is! CancelException) {
      rethrow;
    }
  }
  // 取消任务
  cancelToken.cancel();
}

3. 使用Future队列控制并发量

在高并发网络请求场景下,过多的请求可能导致性能问题或服务器过载。通过Future队列可以控制并发请求的数量。

  • 解决方案
    • 创建一个Future队列,每次从队列中取出一定数量的Future任务并执行,当有任务完成时,再从队列中取出新的任务执行,以此来控制并发量。
  • 代码示例
import 'dart:async';
import 'package:http/http.dart' as http;

void main() async {
  final requests = List.generate(10, (index) =>
      http.get(Uri.parse('https://example.com/$index')));
  final maxConcurrent = 3;
  final completer = Completer();
  var completedCount = 0;
  final queue = Queue<Future<http.Response>>.from(requests);
  final activeTasks = <Future<http.Response>>[];

  void _startNext() {
    while (queue.isNotEmpty && activeTasks.length < maxConcurrent) {
      final task = queue.removeFirst();
      activeTasks.add(task.then((response) {
        print('Response from ${response.request?.url}');
        return response;
      }).whenComplete(() {
        activeTasks.remove(task);
        completedCount++;
        if (completedCount == requests.length) {
          completer.complete();
        } else {
          _startNext();
        }
      }));
    }
  }

  _startNext();
  await completer.future;
}

4. 使用Stream处理异步流数据

Stream可以用于处理一系列异步事件或数据,在高并发场景下,可以通过Stream来处理网络请求的响应流,避免一次性加载大量数据导致的内存问题。

  • 解决方案
    • 使用StreamController创建一个流,网络请求的响应数据可以通过流来逐步处理,而不是一次性加载到内存中。
  • 代码示例
import 'dart:async';
import 'package:http/http.dart' as http;

void main() async {
  final controller = StreamController<String>();
  final response = await http.get(Uri.parse('https://example.com'));
  final stream = response.bodyBytes.asByteStream();
  stream.transform(utf8.decoder).listen((data) {
    controller.add(data);
  }, onDone: () {
    controller.close();
  });

  controller.stream.listen((chunk) {
    print('Received chunk: $chunk');
  });
}