Quarterly maintenance on isolate_example (#142)

pull/145/head
Andrew Brogdon 5 years ago committed by GitHub
parent 7a63156650
commit 0f3721f696
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,7 +10,7 @@ match any new language/SDK features, etc.).
| chrome-os-best-practices | | |
| experimental | | |
| flutter_maps_firestore | | |
| isolate_example | | |
| isolate_example | redbrogdon | 9/12/19 |
| jsonexample | | |
| material_studies/shrine | | |
| place_tracker | | |

@ -15,8 +15,10 @@
*.iws
.idea/
# Visual Studio Code related
.vscode/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
@ -59,6 +61,7 @@
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
@ -68,4 +71,3 @@
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
bash: parse_git_branch: command not found

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 2d2a1ffec95cc70a3218872a2cd3f8de4933c42f
channel: stable
project_type: app

@ -0,0 +1,13 @@
package dev.flutter.isolate_example
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
}
}

@ -0,0 +1,13 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

@ -15,10 +15,16 @@
import 'package:flutter/material.dart';
import 'page_one.dart';
import 'page_two.dart';
import 'page_three.dart';
import 'page_two.dart';
void main() => runApp(MaterialApp(home: StartApp()));
void main() {
runApp(
MaterialApp(
home: StartApp(),
),
);
}
class StartApp extends StatelessWidget {
@override
@ -30,9 +36,18 @@ class StartApp extends StatelessWidget {
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Icon(Icons.flash_on), text: 'Performance'),
Tab(icon: Icon(Icons.sync), text: 'Infinite Process'),
Tab(icon: Icon(Icons.storage), text: 'Data Transfer'),
Tab(
icon: Icon(Icons.flash_on),
text: 'Performance',
),
Tab(
icon: Icon(Icons.sync),
text: 'Infinite Process',
),
Tab(
icon: Icon(Icons.storage),
text: 'Data Transfer',
),
],
),
title: Text('Isolate Example'),

@ -15,6 +15,20 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// Computes the nth number in the Fibonacci sequence.
int fib(int n) {
int number1 = n - 1;
int number2 = n - 2;
if (n == 1) {
return 0;
} else if (n == 0) {
return 1;
} else {
return (fib(number1) + fib(number2));
}
}
class PerformancePage extends StatefulWidget {
@override
_PerformancePageState createState() => _PerformancePageState();
@ -65,7 +79,9 @@ class _PerformancePageState extends State<PerformancePage> {
}
VoidCallback createMainIsolateCallBack(
BuildContext context, AsyncSnapshot snapshot) {
BuildContext context,
AsyncSnapshot snapshot,
) {
if (snapshot.connectionState == ConnectionState.done) {
return () {
setState(() {
@ -101,27 +117,20 @@ class _PerformancePageState extends State<PerformancePage> {
return null;
}
}
}
Future<void> computeOnMainIsolate() async {
// The isolate will need a little time to disable the buttons before the performance hit.
await Future.delayed(Duration(milliseconds: 100), () => fib(45));
}
Future<void> computeOnMainIsolate() async {
// A delay is added here to give Flutter the chance to redraw the UI at least
// once before the computation (which, since it's run on the main isolate,
// will lock up the app) begins executing.
await Future.delayed(
Duration(milliseconds: 100),
() => fib(45),
);
}
Future<void> computeOnSecondaryIsolate() async {
Future<void> computeOnSecondaryIsolate() async {
// Compute the Fibonacci series on a secondary isolate.
await compute(fib, 45);
}
int fib(int n) {
int number1 = n - 1;
int number2 = n - 2;
if (n == 1) {
return 0;
} else if (n == 0) {
return 1;
} else {
return (fib(number1) + fib(number2));
}
}
@ -133,44 +142,32 @@ class SmoothAnimationWidget extends StatefulWidget {
class SmoothAnimationWidgetState extends State<SmoothAnimationWidget>
with TickerProviderStateMixin {
AnimationController _controller;
Animation<BorderRadius> borderRadius;
Animation<BorderRadius> _borderAnimation;
@override
void initState() {
super.initState();
_controller =
AnimationController(duration: const Duration(seconds: 1), vsync: this)
..addStatusListener(
(status) {
if (status == AnimationStatus.completed) {
_controller.reverse();
} else if (status == AnimationStatus.dismissed) {
_controller.forward();
}
},
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
borderRadius = BorderRadiusTween(
_borderAnimation = BorderRadiusTween(
begin: BorderRadius.circular(100.0),
end: BorderRadius.circular(0.0),
).animate(
CurvedAnimation(
parent: _controller,
curve: Curves.linear,
),
);
).animate(_controller);
_controller.forward();
_controller.repeat(reverse: true);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: borderRadius,
builder: (context, child) {
return Center(
child: Container(
child: AnimatedBuilder(
animation: _borderAnimation,
builder: (context, child) {
return Container(
child: FlutterLogo(
size: 200,
),
@ -180,13 +177,16 @@ class SmoothAnimationWidgetState extends State<SmoothAnimationWidget>
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
colors: [Colors.blueAccent, Colors.redAccent],
),
borderRadius: borderRadius.value,
colors: [
Colors.blueAccent,
Colors.redAccent,
],
),
borderRadius: _borderAnimation.value,
),
);
},
),
);
}

@ -11,9 +11,11 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import 'dart:typed_data';
import 'dart:isolate';
import 'dart:math';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -30,6 +32,8 @@ class DataTransferPageStarter extends StatelessWidget {
class DataTransferPage extends StatelessWidget {
@override
Widget build(context) {
final controller = Provider.of<DataTransferIsolateController>(context);
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
@ -42,17 +46,34 @@ class DataTransferPage extends StatelessWidget {
padding: EdgeInsets.all(8),
),
LinearProgressIndicator(
value: Provider.of<DataTransferIsolateController>(context)
.progressPercent,
value: controller.progressPercent,
backgroundColor: Colors.grey[200],
),
Expanded(child: RunningList()),
Expanded(
child: RunningList(),
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [createButtons(context)],
RaisedButton(
child: const Text('Transfer Data to 2nd Isolate'),
color: (controller.runningTest == 1)
? Colors.blueAccent
: Colors.grey[300],
onPressed: () => controller.generateRandomNumbers(false),
),
RaisedButton(
child: const Text('Transfer Data with TransferableTypedData'),
color: (controller.runningTest == 2)
? Colors.blueAccent
: Colors.grey[300],
onPressed: () => controller.generateRandomNumbers(true),
),
RaisedButton(
child: const Text('Generate on 2nd Isolate'),
color: (controller.runningTest == 3)
? Colors.blueAccent
: Colors.grey[300],
onPressed: controller.generateOnSecondaryIsolate,
),
],
),
@ -63,33 +84,39 @@ class DataTransferPage extends StatelessWidget {
}
class DataTransferIsolateController extends ChangeNotifier {
Isolate _newIsolate;
ReceivePort _mIceRP;
SendPort _newIceSP;
Isolate _isolate;
ReceivePort _incomingReceivePort;
SendPort _outgoingSendPort;
final currentProgress = <String>[];
int runningTest = 0;
Stopwatch _timer = Stopwatch();
double progressPercent = 0;
Isolate get newIsolate => _isolate;
bool get running => runningTest != 0;
DataTransferIsolateController() {
createIsolate();
listen();
}
Future<void> createIsolate() async {
_mIceRP = ReceivePort();
_newIsolate =
await Isolate.spawn(_secondIsolateEntryPoint, _mIceRP.sendPort);
_incomingReceivePort = ReceivePort();
_isolate = await Isolate.spawn(
_secondIsolateEntryPoint, _incomingReceivePort.sendPort);
}
void listen() {
_mIceRP.listen((dynamic message) {
if (message is SendPort) _newIceSP = message;
_incomingReceivePort.listen((dynamic message) {
if (message is SendPort) {
_outgoingSendPort = message;
}
if (message is int) {
currentProgress.insert(
0, '$message% - ${_timer.elapsedMilliseconds / 1000} Sec');
0, '$message% - ${_timer.elapsedMilliseconds / 1000} seconds');
progressPercent = message / 100;
}
@ -109,7 +136,7 @@ class DataTransferIsolateController extends ChangeNotifier {
_timer = Stopwatch();
_timer.start();
_newIceSP.send('start');
_outgoingSendPort.send('start');
notifyListeners();
}
@ -150,26 +177,22 @@ class DataTransferIsolateController extends ChangeNotifier {
Future<void> sendNumbers(dynamic numList) async {
return Future<void>(() {
_newIceSP.send(numList);
_outgoingSendPort.send(numList);
});
}
Isolate get newIsolate => _newIsolate;
bool get running => runningTest != 0;
void dispose() {
super.dispose();
_newIsolate?.kill(priority: Isolate.immediate);
_newIsolate = null;
_isolate?.kill(priority: Isolate.immediate);
_isolate = null;
}
}
class RunningList extends StatelessWidget {
@override
Widget build(BuildContext context) {
final controller = Provider.of<DataTransferIsolateController>(context);
final progress = controller.currentProgress;
final progress =
Provider.of<DataTransferIsolateController>(context).currentProgress;
return DecoratedBox(
decoration: BoxDecoration(
@ -234,7 +257,10 @@ Iterable<int> createNums() sync* {
}
Future<void> generateAndSum(
SendPort callerSP, Iterable<int> iter, int length) async {
SendPort callerSP,
Iterable<int> iter,
int length,
) async {
int sum = 0;
int count = 1;
@ -248,41 +274,3 @@ Future<void> generateAndSum(
return sum;
}
Widget createButtons(BuildContext context) {
final controller =
Provider.of<DataTransferIsolateController>(context, listen: false);
return ButtonBar(
alignment: MainAxisAlignment.center,
children: [
Column(
children: [
RaisedButton(
child: const Text('Transfer Data to 2nd Isolate'),
elevation: 8.0,
color: (controller.runningTest == 1)
? Colors.blueAccent
: Colors.grey[300],
onPressed: () => controller.generateRandomNumbers(false),
),
RaisedButton(
child: const Text('Transfer Data with TransferableTypedData'),
elevation: 8.0,
color: (controller.runningTest == 2)
? Colors.blueAccent
: Colors.grey[300],
onPressed: () => controller.generateRandomNumbers(true),
),
RaisedButton(
child: const Text('Generate on 2nd Isolate'),
elevation: 8.0,
color: (controller.runningTest == 3)
? Colors.blueAccent
: Colors.grey[300],
onPressed: controller.generateOnSecondaryIsolate,
),
],
),
],
);
}

@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'dart:isolate';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class InfiniteProcessPageStarter extends StatelessWidget {
@override
Widget build(context) {
@ -32,28 +33,40 @@ class InfiniteProcessPage extends StatelessWidget {
Widget build(context) {
final controller = Provider.of<InfiniteProcessIsolateController>(context);
return Column(
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Summation Results',
style: Theme.of(context).textTheme.title,
),
padding: EdgeInsets.all(8),
),
Expanded(child: RunningList()),
SafeArea(
child: Column(
Expanded(
child: RunningList(),
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [newButtons(context)],
ButtonBar(
alignment: MainAxisAlignment.center,
children: [
RaisedButton(
child: const Text('Start'),
elevation: 8.0,
onPressed: () => controller.start(),
),
RaisedButton(
child: const Text('Terminate'),
elevation: 8.0,
onPressed: () => controller.terminate(),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Switch(
value: !controller.paused,
@ -66,11 +79,23 @@ class InfiniteProcessPage extends StatelessWidget {
Text('Pause/Resume'),
],
),
radioButtonWidget(context),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (int i = 1; i <= 3; i++) ...[
Radio<int>(
value: i,
groupValue: controller.currentMultiplier,
onChanged: (val) => controller.setMultiplier(val),
),
Text('${i}x')
],
],
),
],
),
],
),
);
}
}
@ -83,9 +108,17 @@ class InfiniteProcessIsolateController extends ChangeNotifier {
int _currentMultiplier = 1;
List<int> _currentResults = [];
bool _running = false;
bool _created = false;
bool _paused = false;
int get currentMultiplier => _currentMultiplier;
bool get paused => _paused;
bool get created => _created;
List<int> get currentResults => _currentResults;
Future<void> createIsolate() async {
mIceRP = ReceivePort();
newIsolate = await Isolate.spawn(_secondIsolateEntryPoint, mIceRP.sendPort);
@ -103,23 +136,28 @@ class InfiniteProcessIsolateController extends ChangeNotifier {
}
Future<void> start() async {
if (_running == false && _paused == false) {
if (_created == false && _paused == false) {
await createIsolate();
listen();
_running = true;
_created = true;
notifyListeners();
}
}
void terminate() {
newIsolate.kill();
_running = false;
_created = false;
_currentResults.clear();
notifyListeners();
}
void pausedSwitch() {
(_paused) ? newIsolate.resume(capability) : capability = newIsolate.pause();
if (_paused) {
newIsolate.resume(capability);
} else {
capability = newIsolate.pause();
}
_paused = !_paused;
notifyListeners();
}
@ -135,18 +173,10 @@ class InfiniteProcessIsolateController extends ChangeNotifier {
notifyListeners();
}
int get multiplier => _currentMultiplier;
bool get paused => _paused;
bool get running => _running;
List<int> get currentResults => _currentResults;
void dispose() {
super.dispose();
newIsolate?.kill(priority: Isolate.immediate);
newIsolate = null;
super.dispose();
}
}
@ -171,7 +201,7 @@ class RunningList extends StatelessWidget {
leading: Text('${sums.length - index}.'),
title: Text('${sums[index]}.'),
),
color: (controller.running && !controller.paused)
color: (controller.created && !controller.paused)
? Colors.lightGreenAccent
: Colors.deepOrangeAccent,
),
@ -197,77 +227,28 @@ Future<void> _secondIsolateEntryPoint(SendPort callerSP) async {
if (message is int) multiplyValue = message;
});
int forEnd = 10000;
// This runs until the isolate is terminated.
while (true) {
int sum = 0;
for (int i = 0; i < forEnd; i++) {
sum += await brokenUpComputation(1000);
for (int i = 0; i < 10000; i++) {
sum += await doSomeWork();
}
forEnd += 10;
callerSP.send(sum * multiplyValue);
}
}
Future<int> brokenUpComputation(int num) {
Future<int> doSomeWork() {
Random rng = Random();
return Future(() {
int sum = 0;
for (int i = 0; i < num; i++) {
for (int i = 0; i < 1000; i++) {
sum += rng.nextInt(100);
}
return sum;
});
}
Widget newButtons(BuildContext context) {
final controller =
Provider.of<InfiniteProcessIsolateController>(context, listen: false);
return ButtonBar(
alignment: MainAxisAlignment.center,
children: [
RaisedButton(
child: const Text('Start'),
elevation: 8.0,
onPressed: () => controller.start(),
),
RaisedButton(
child: const Text('Terminate'),
elevation: 8.0,
onPressed: () => controller.terminate(),
),
],
);
}
Widget radioButtonWidget(BuildContext context) {
final controller = Provider.of<InfiniteProcessIsolateController>(context);
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Radio(
value: 1,
groupValue: controller.multiplier,
onChanged: (dynamic _) => controller.setMultiplier(1),
),
Text('1x'),
Radio(
value: 2,
groupValue: controller.multiplier,
onChanged: (dynamic _) => controller.setMultiplier(2),
),
Text('2x'),
Radio(
value: 3,
groupValue: controller.multiplier,
onChanged: (dynamic _) => controller.setMultiplier(3),
),
Text('3x'),
],
);
}

@ -29,13 +29,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.11"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
flutter:
dependency: "direct main"
description: flutter
@ -80,7 +73,7 @@ packages:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0+1"
version: "3.1.0"
quiver:
dependency: transitive
description:

@ -8,13 +8,12 @@ environment:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
provider: ^3.0.0
provider: ^3.1.0
dev_dependencies:
flutter_test:
sdk: flutter
pedantic: ^1.7.0
pedantic: ^1.8.0+1
flutter:

Loading…
Cancel
Save