Pause an async function until a condition is met in dart

192

Streams are the best fit for such scenarios. Consider the following..

import 'dart:async';

// creating a stream
StreamController<String> streamController = StreamController();

void main(){
  
  // stream listener
  streamController.stream.listen((value){
    print(value); // print message to terminal
  });
  
  // adding object to stream
  streamController.add("hello");
  streamController.add("bye");
  streamController.add("seeya");
}

Here, whenever you add an object (in this case a string) into the stream, the listener is called which executes whatever you have defined inside it. In my case, the code will print hello bye and seeya to the terminal.

Similarly, you can use stream to fire up some piece of code whenever you add something to the stream.

Share:
192
Fabrizio
Author by

Fabrizio

Updated on January 03, 2023

Comments

  • Fabrizio
    Fabrizio over 1 year

    I have a widget that performs a series of expensive computations (which are carried out on a compute core). The computations are queued in a list in the widget and the computation of each is waited for. The computations are queued in the build function so since before being sent to the compute core require some computations to be performed on the main isolate, I thought not to handle them directly in the build function but to just add them to the queue at build time.

    This is the function I currently have to exhaust the queue:

    void emptyQueue() async {
    
      while(queue.isNotEmpty) {
        /* Perform some computations here, which prevents me from just sending the data to the compute core directly (they need data that is only in the main isolate and it's too big to send to the compute core) */
    
        /* Send the data to the worker isolate */
        await Future.delayed(Duration(milliseconds: 1000));
    
        /* Remove the first element from the queue. */
        queue.removeFirst();
      }
    }
    

    This function works well when the function is called as the queue is fixed and no more elements are added to it afterward as it just loops until the queue is empty. My problem is that I can add requests to the queue at any point in time, even when the queue is empty, and by then the function would be completely done and thus the queue would not be exhausted anymore.

    I thought something like this might work but so far I wasn't able to concretely implement it.

    void emptyQueue() async {
        while (true) {
          if (queue.isNotEmpty()) {
            /* Perform some computations here (gather data to send to the compute core) */
    
            /* Send the data to the worker isolate */
            await Future.delayed(Duration(milliseconds: 1000));
    
            /* Remove the first element from the queue. */
            queue.removeFirst();
          }
    
          await /* a signal of some sort */;
        }
      }
    

    In this way, I could start the emptyQueue in the initState as it would be paused until something is added to the queue. Moreover, the function which would be called at build time would be just queue.add(item), without any of the main isolate-side computations.

    Is there any way I could pause the function at the end (at the last await)?

    • pskink
      pskink about 2 years
      use streams and IsolateChannel
    • Fabrizio
      Fabrizio about 2 years
      Thank you for your answer, I've looked on the example at medium.com/@flutterhive/…, but it seems that by using this method, the heavish computations before sending the data to the computation isolate would be performed in the build function as they would be run at the time the item is added to the queue. Have I misunderstood something?
    • pskink
      pskink about 2 years
      what do you mean by the heavish computations? making heavy / long computations is what Isolate is used for - it means you should perform them in your Isolate
    • Fabrizio
      Fabrizio about 2 years
      There are computations which require data which is in the main thread, for example I need to extract long substrings from very long strings, which from my benchmarks seemed to take up a bit of time, so I wanted to prevent them happening inside the build function. I don't think I can execute them on the isolate as, if I understood correctly I would need to send a lot of data to the isolate which I think might slow things down. The isolate needs to perform operations on the substrings I pass it, for example count the number of times a character appears and so on.