Flutter异步性能测试插件async_benchmark的使用

发布于 1周前 作者 songsunli 来自 Flutter

Flutter异步性能测试插件async_benchmark的使用

async_benchmark 是一个用于运行和分析基准测试的Dart包,支持隔离环境和性能跟踪。

使用

import 'dart:math';

import 'package:async_benchmark/async_benchmark.dart';

void main() async {
  final profile = 
  BenchmarkProfile('custom', warmup: 10, interactions: 100, rounds: 3);

  await BenchmarkPrime(seed: 12345).run(profile: profile, verbose: true);
}

class BenchmarkPrime extends Benchmark<int, Prime> {
  final int? seed;

  BenchmarkPrime({this.seed}) : super('PrimeCounter(seed: ${seed ?? '*'})');

  @override
  BenchmarkSetupResult<int, Prime> setup() {
    var prime = Prime();

    var rand = Random(seed);
    var limit = rand.nextInt(999999);

    return (setup: limit, service: prime);
  }

  @override
  void job(int setup, Prime? service) {
    var prime = service ?? Prime();
    prime.countPrimes(setup);
  }
}

class Prime {
  int countPrimes(int limit) {
    var count = 0;
    for (var n = 2; n <= limit; ++n) {
      if (isPrime(n)) {
        ++count;
      }
    }
    return count;
  }

  bool isPrime(int n) {
    if (n <= 1) return false;
    if (n == 2) return true;

    if (n % 2 == 0) return false;

    var sqr = sqrt(n);

    for (var b = 3; b <= sqr; b += 2) {
      if (n % b == 0) return false;
    }

    return true;
  }

  @override
  String toString() => 'Prime{}';
}

输出结果

╔═══════════════════════════╗
║ PrimeCounter(seed: 12345) ║
╠═══════════════════════════╝
║ BenchmarkProfile[custom]{warmup: 10, interactions: 100, rounds: 3}
╠────────────────────────────
║ Setup...
║ ─ (service: Prime{}, setup: 155253)
║ Warmup (10)...
╠────────────────────────────
║ ROUND: 1/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:01.356317
║ »» Speed: 73.7291 Hz
║ »» Interaction Time: 13.563 ms
╠────────────────────────────
║ ROUND: 2/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:01.352660
║ »» Speed: 73.9284 Hz
║ »» Interaction Time: 13.527 ms
╠────────────────────────────
║ ROUND: 3/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:01.359452
║ »» Speed: 73.5591 Hz
║ »» Interaction Time: 13.595 ms
╠────────────────────────────
║ BEST ROUND: 2
║
║ »» Duration: 0:00:01.352660
║ »» Speed: 73.9284 Hz
║ »» Interaction Time: 13.527 ms
╠────────────────────────────
║ Shutdown...
╚════════════════════════════

完整示例Demo

以下是一个完整的示例,展示了如何使用 async_benchmark 运行多个基准测试并比较它们的性能。

import 'dart:collection';
import 'dart:math';

import 'package:async_benchmark/async_benchmark.dart';

void main() async {
  final profile = 
      BenchmarkProfile('custom', warmup: 10, interactions: 100, rounds: 3);

  final seed = 123;

  var benchmarks = <Benchmark<int, Prime>>[
    BenchmarkPrimeCached(seed: seed),
    BenchmarkPrime(seed: seed),
  ];

  await benchmarks.runAll(profile: profile, verbose: true);
}

class BenchmarkPrimeCached extends Benchmark<int, PrimeCached> {
  final int? seed;

  BenchmarkPrimeCached({this.seed})
      : super('PrimeCounterCached(seed: ${seed ?? '*'})');

  static final Pool<PrimeCached> _primePool = Pool(() => PrimeCached());

  @override
  BenchmarkSetupResult<int, PrimeCached> setup() {
    var prime = _primePool.catchElement();

    var rand = Random(seed);
    var limit = rand.nextInt(999999);

    return (setup: limit, service: prime);
  }

  @override
  void job(int setup, Prime? service) {
    var prime = service ?? _primePool.catchElement();
    prime.countPrimes(setup);
  }

  @override
  void teardown(int setup, PrimeCached? service) async {
    if (service != null) {
      service.clearCache();
    }
  }

  @override
  void shutdown(int setup, PrimeCached? service) async {
    if (service != null) {
      _primePool.releaseElement(service);
    }
  }
}

class BenchmarkPrime extends Benchmark<int, Prime> {
  final int? seed;

  BenchmarkPrime({this.seed}) : super('PrimeCounter(seed: ${seed ?? '*'})');

  @override
  BenchmarkSetupResult<int, Prime> setup() {
    var prime = Prime();

    var rand = Random(seed);
    var limit = rand.nextInt(999999);

    return (setup: limit, service: prime);
  }

  @override
  void job(int setup, Prime? service) {
    var prime = service ?? Prime();
    prime.countPrimes(setup);
  }
}

class PrimeCached extends Prime {
  final Set<int> _primesCache = {};

  int get cacheLength => _primesCache.length;

  void clearCache() {
    _primesCache.clear();
    _isPrimeCached = 0;
    _isPrimeComputed = 0;
  }

  int _isPrimeCached = 0;
  int _isPrimeComputed = 0;

  ({int cached, int computed}) get isPrimeStats => 
      (cached: _isPrimeCached, computed: _isPrimeComputed);

  @override
  bool isPrime(int n) {
    if (n <= 1) return false;
    if (n == 2) return true;

    if (n % 2 == 0) return false;

    if (_primesCache.contains(n)) {
      ++_isPrimeCached;
      return true;
    }

    var sqr = sqrt(n);

    for (var b = 3; b <= sqr; b += 2) {
      if (n % b == 0) return false;
    }

    ++_isPrimeComputed;
    _primesCache.add(n);

    return true;
  }

  @override
  String toString() => 'PrimeCached{cache: ${_primesCache.length}}';
}

class Prime {
  int countPrimes(int limit) {
    var count = 0;
    for (var n = 2; n <= limit; ++n) {
      if (isPrime(n)) {
        ++count;
      }
    }
    return count;
  }

  bool isPrime(int n) {
    if (n <= 1) return false;
    if (n == 2) return true;

    if (n % 2 == 0) return false;

    var sqr = sqrt(n);

    for (var b = 3; b <= sqr; b += 2) {
      if (n % b == 0) return false;
    }

    return true;
  }

  @override
  String toString() => 'Prime{}';
}

class Pool<E extends Object> {
  final E Function() instantiator;

  Pool(this.instantiator);

  final Queue<E> _pool = Queue();

  E catchElement() {
    if (_pool.isEmpty) {
      return instantiator();
    } else {
      return _pool.removeLast();
    }
  }

  bool releaseElement(E? element) {
    if (element != null && _pool.length < 10) {
      _pool.add(element);
      return true;
    } else {
      return false;
    }
  }
}

输出结果

╔═══════════════════════════════╗
║ PrimeCounterCached(seed: 123) ║
╠═══════════════════════════════╝
║ BenchmarkProfile[custom]{warmup: 10, interactions: 100, rounds: 3}
╠────────────────────────────────
║ Setup...
║ ─ (service: PrimeCached{cache: 0}, setup: 999502)
║ Warmup (10)...
╠────────────────────────────────
║ ROUND: 1/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:06.366585
║ »» Speed: 15.7070 Hz
║ »» Interaction Time: 63.666 ms
╠────────────────────────────────
║ ROUND: 2/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:06.548992
║ »» Speed: 15.2695 Hz
║ »» Interaction Time: 65.490 ms
╠────────────────────────────────
║ ROUND: 3/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:06.541619
║ »» Speed: 15.2867 Hz
║ »» Interaction Time: 65.416 ms
╠────────────────────────────────
║ BEST ROUND: 1
║
║ »» Duration: 0:00:06.366585
║ »» Speed: 15.7070 Hz
║ »» Interaction Time: 63.666 ms
╠────────────────────────────────
║ Shutdown...
╚════════════════════════════════

╔═════════════════════════╗
║ PrimeCounter(seed: 123) ║
╠═════════════════════════╝
║ BenchmarkProfile[custom]{warmup: 10, interactions: 100, rounds: 3}
╠──────────────────────────
║ Setup...
║ ─ (service: Prime{}, setup: 999502)
║ Warmup (10)...
╠──────────────────────────
║ ROUND: 1/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:17.028856
║ »» Speed: 5.8724 Hz
║ »» Interaction Time: 170.289 ms
╠──────────────────────────
║ ROUND: 2/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:16.985658
║ »» Speed: 5.8873 Hz
║ »» Interaction Time: 169.857 ms
╠──────────────────────────
║ ROUND: 3/3
║
║ ─ Running (100)...
║ ─ Teardown...
║
║ »» Duration: 0:00:17.001885
║ »» Speed: 5.8817 Hz
║ »» Interaction Time: 170.019 ms
╠──────────────────────────
║ BEST ROUND: 2
║
║ »» Duration: 0:00:16.985658
║ »» Speed: 5.8873 Hz
║ »» Interaction Time: 169.857 ms
╠──────────────────────────
║ Shutdown...
╚══════════════════════════

╔════════════════════════════════
║ BEST BENCHMARK: PrimeCounterCached(seed: 123) (round: 1)
║
║ »» Duration: 0:00:06.366585
║ »» Speed: 15.7070 Hz
║ »» Interaction Time: 63.666 ms
╠────────────────────────────────
║ BENCHMARK: PrimeCounter(seed: 123) (round: 2)
║ »» Duration: 0:00:16.985658
║ »» Speed: 5.8873 Hz
║ »» Interaction Time: 169.857 ms
║ »» Speed ratio: 0.3748 (2.6679 x)
╚════════════════════════════════

更多关于Flutter异步性能测试插件async_benchmark的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter异步性能测试插件async_benchmark的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter异步性能测试插件async_benchmark的代码示例。async_benchmark是一个用于测量Flutter应用中异步操作执行时间的工具。

首先,确保你已经在你的pubspec.yaml文件中添加了async_benchmark依赖:

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

然后,运行flutter pub get来安装依赖。

接下来,你可以在你的Flutter应用中使用async_benchmark来测量异步操作的性能。以下是一个示例代码:

import 'package:flutter/material.dart';
import 'package:async_benchmark/async_benchmark.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Async Benchmark Example'),
        ),
        body: Center(
          child: AsyncBenchmarkButton(),
        ),
      ),
    );
  }
}

class AsyncBenchmarkButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () async {
        // 使用async_benchmark来测量异步操作的性能
        final benchmark = await runAsyncBenchmark('measure async operation') {
          // 在这里放置你要测量的异步操作
          await Future.delayed(Duration(seconds: 2));
        };

        // 打印结果
        print('Benchmark result: ${benchmark.toJson()}');

        // 你可以在UI中显示结果,例如使用Snackbar
        ScaffoldMessenger.of(context).showSnackbar(
          Snackbar(
            content: Text(
              'Async operation took ${benchmark.averageDuration.inMilliseconds}ms on average',
            ),
          ),
        );
      },
      child: Text('Measure Async Operation'),
    );
  }
}

在这个示例中,我们创建了一个Flutter应用,其中包含一个按钮。当点击按钮时,会触发一个异步操作(在这个例子中是Future.delayed模拟的2秒延迟),并使用async_benchmark来测量这个操作的性能。

runAsyncBenchmark函数接受一个描述性字符串(用于标识测量的操作)和一个闭包(包含要测量的异步操作)。它返回一个BenchmarkResult对象,你可以打印或显示这个结果。

BenchmarkResult对象包含了多个有用的属性,如averageDuration(平均持续时间)、minDuration(最小持续时间)、maxDuration(最大持续时间)等。

注意:在实际应用中,你应该将Future.delayed替换为你想要测量的实际异步操作。

这个示例展示了如何使用async_benchmark来测量和显示异步操作的性能,从而帮助你优化你的Flutter应用。

回到顶部