2

I'm learning about Flutter's compute function. My understanding of it is that it's for offloading computationally heavy work to another thread so as not to block the UI thread. I've come across some behaviour I don't quite understand. Consider the app below.

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

void main() => runApp(new MyApp());

class StringValues {
  static String foo = 'Foo';
  static String bar;
}

String _calculate(String value) {
  return value + ' ' + (StringValues.foo ?? 'undefined') + ' ' + (StringValues.bar ?? 'undefined');
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  void _testCompute() async {
    String result1 = _calculate('values are:');
    String result2 = await compute(_calculate, 'values are:');

    StringValues.bar = 'Bar';

    String result3 = _calculate('values are:');
    String result4 = await compute(_calculate, 'values are:');

    print(result1);
    print(result2);
    print(result3);
    print(result4);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _testCompute,
        child: new Icon(Icons.print),
      ),
    );
  }
}

The output of the _testCompute function is:

values are: Foo undefined
values are: Foo undefined
values are: Foo Bar
values are: Foo undefined

It compiles fine. I would expect result4 to be the same as result3. Can anyone explain why it's not? I also tried a different approach using 'globals' as described here, but the result was the same.

hunter
  • 872
  • 10
  • 26

1 Answers1

6

compute() creates a new isolate. Isolates started this way share nothing except code.
It is similar as if you would start a new process with the same project just with _calculate as the entry point instead of main.

compute passes 'values are:' to the isolate using a SendPort/ReceivePort combination and the value is then passed to _calculate as parameter when the isolate starts running.

The values are passed by value, so passing an object reference and changing it on the other side won't have any effect on the sender side.

Again the isolates share no state, only code and they communicate using SendPort/ReceivePort to pass values back and forth between the main isolate and the "compute" isolate.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567