How to pass message to isolate and handle error
Asked Answered
I

1

8

I am trying to use dart isolate library to improve my application performance.

Look at following code:

import 'dart:isolate';
import 'package:dbcrypt/dbcrypt.dart';

main() {

  var pwConPort = new ReceivePort();
  pwConPort.listen((data) {
      print(data);
      pwConPort.close();
  }, onError: (err) {
      print(err);
  });

  Isolate.spawn(generatePasswordConcurrency, pwConPort.sendPort);

}

void generatePasswordConcurrency(SendPort sendPort) {
    sendPort.send(_generateHashPassword('Passsowr1222!'));

}

String _generateHashPassword(String password) {
    var regex = new RegExp(r'^.*(?=.{7,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).*$');
    if (!regex.hasMatch(password)) {
        throw new StateError('Errors');
    }
    return new DBCrypt().hashpw(password, new DBCrypt().gensalt());
}

Everything works fine but i can only pass a static password, or better to say, i don't know, how to pass something dynamically. Here you can see, password is hardcoded, but i want to pass a variable for example.

void generatePasswordConcurrency(SendPort sendPort) {
    sendPort.send(_generateHashPassword('Passsowr1222!'));

}

If the method _generateHashPassword will throw an error, how can I handling this error? I try to catch the error on listen method from ReceivePort

  pwConPort.listen((data) {
      print(data);
      pwConPort.close();
  }, onError: (err) {
      print(err);
  });

but still got unhandling exceptions message.

Observatory listening on http://127.0.0.1:51433
in ShutdownIsolate: Unhandled exception:
Bad state: Errors
#0      _generateHashPassword (file:///D:/Dart/samples/bin/isolate_error.dart:26:9)
#1      generatePasswordConcurrency (file:///D:/Dart/samples/bin/isolate_error.dart:19:40)
#2      _startIsolate.isolateStartHandler (dart:isolate-patch/isolate_patch.dart:221)
#3      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:124)

Conclusion my question:

How can I pass a variable to called method on isolate?
How can I handling error on isolate?

Isolating answered 3/7, 2014 at 9:50 Comment(0)
G
20

First of all,

Isolate are not thread, they are independant process more like a fork() than a thread

dartApi: Isolate

Concurrent programming using isolates: independent workers that are similar to threads but don't share memory, communicating only via messages.

So, you can't access to the same variable than your parent process. It's a choice made by the dart team, because it's a mechanism usable when you compile your dart code in js. So it need to be possible in JS

How can I pass a variable to called method on isolate?

To do this, you need to see ReceivePort() like a unidirectionnal way of communication, so to pass variable in two way, you need two.

So on you main process:

pwConPort.listen((data) {
      if (isolateSendPort == null && data is SendPort) {
        isolateSendPort = data; // Receive the communication object of the isolate
        isolateSendPort.send("Passsowr1222!");
      } else {
        print("Generated password: ${data}");
        pwConPort.close();
      }
    }, onError: (err) {
      print("SendPortError: ${err}");
    });
  });

In you isolate entry point :

 sendPort.send(isolateConPort.sendPort);
    isolateConPort.listen((data) {
      // code ....
    });

Note: be careful of what message you send. message send between one process and another need to respect some rules

DartApi: SendPort

The content of message can be: primitive values (null, num, bool, double, String), instances of SendPort, and lists and maps whose elements are any of these. List and maps are also allowed to be cyclic.

How can I handling error on isolate?

Isolate get one method to listen throw error send by the isolate : addErrorListner That is a useful function.

BUT ! this method is not implement in every plate-forme, so you need to do this in a others.

The way i chose is to send 2 SendPort in the entry point function :

  • One for the communication

  • One for the error.

So the spawn function looks like :

Isolate.spawn(generatePasswordConcurrency, [pwConPort.sendPort, errorPort.sendPort])

and the generatePasswordConcurrency :

void generatePasswordConcurrency(List<SendPort> commList) {
    var sendPort = commList[0];
    var errorPort = commList[1];
    var isolateConPort = new ReceivePort();
    sendPort.send(isolateConPort.sendPort);
    isolateConPort.listen((data) {
      try {
        sendPort.send(_generateHashPassword(data));
      } catch (e) {
        errorPort.send("error: ${e.toString()}");
      }
    });
}

Here the full code :

import 'dart:isolate';
import 'package:dbcrypt/dbcrypt.dart';

main() {

  var pwConPort = new ReceivePort();
  var errorPort = new ReceivePort();
  SendPort isolateSendPort = null;

  Isolate.spawn(generatePasswordConcurrency, [pwConPort.sendPort, errorPort.sendPort])
  .then((Isolate pcs) {
    errorPort.listen((err) {
      print("Error: ${err}");
      pwConPort.close();
      errorPort.close();
    });
    print(pcs);

    pwConPort.listen((data) {
      if (isolateSendPort == null && data is SendPort) {
        isolateSendPort = data;
        isolateSendPort.send("Passsowr1222!");
      } else {
        print("Generated password: ${data}");
        pwConPort.close();
        errorPort.close();
        //pcs.kill();
      }
    }, onError: (err) {
      print("SendPortError: ${err}");
    });
  });
}

void generatePasswordConcurrency(List<SendPort> commList) {
    var sendPort = commList[0];
    var errorPort = commList[1];
    var isolateConPort = new ReceivePort();
    sendPort.send(isolateConPort.sendPort);
    isolateConPort.listen((data) {
      try {
        sendPort.send(_generateHashPassword(data));
      } catch (e) {
        errorPort.send("error: ${e.toString()}");
      }
    });
}

String _generateHashPassword(String password) {
  var regex = new RegExp(r'^.*(?=.{7,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).*$');
  if (!regex.hasMatch(password)) {
    throw new StateError('Errors');
  }
  return new DBCrypt().hashpw(password, new DBCrypt().gensalt());
}
Giulio answered 3/7, 2014 at 13:20 Comment(4)
And what is c function?Isolating
It is not possible to use isolate on frontend right only backend?Isolating
It's possible, but it's maybe a bit more complicateGiulio
@zero_coding: Command line apps may use Isolate.spawn(). Web apps can spawn isolates but must use Isolate.spawnUri().Tagmemics

© 2022 - 2024 — McMap. All rights reserved.