Как передать сообщение, чтобы изолировать и обработать ошибку

Я пытаюсь использовать библиотеку изоляции dart для повышения производительности моего приложения.

Посмотрите на следующий код:

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());
}

Все работает нормально, но я могу передать только статический пароль, или, лучше сказать, я не знаю, как передать что-то динамически. Здесь вы можете видеть, что пароль жестко запрограммирован, но я хочу, например, передать переменную.

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

}

Если метод _generateHashPassword выдаст ошибку, как я могу обработать эту ошибку? Я пытаюсь отловить ошибку при прослушивании метода от ReceivePort

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

но по-прежнему появляется сообщение о необработанном исключении.

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)

Заключение мой вопрос:

Как передать переменную в вызываемый метод при изолировании?
Как я могу обработать ошибку при изолировании?


person softshipper    schedule 03.07.2014    source источник


Ответы (1)


Прежде всего,

Isolate - это не поток, это независимый процесс, больше похожий на fork(), чем на поток

dartApi: Изолировать

Параллельное программирование с использованием изоляторов: независимых рабочих процессов, которые похожи на потоки, но не разделяют память, общаются только через сообщения.

Таким образом, вы не можете получить доступ к той же переменной, что и ваш родительский процесс. Это выбор, сделанный командой dart, потому что это механизм, который можно использовать, когда вы компилируете свой код dart в js. Так что это должно быть возможно в JS

Как передать переменную в вызываемый метод при изоляции?

Для этого вам нужно рассматривать ReceivePort() как однонаправленный способ связи, поэтому для передачи переменной двумя способами вам понадобится два.

Итак, о вашем основном процессе:

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}");
    });
  });

Вы изолируете точку входа:

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

Примечание. Будьте осторожны с тем, какое сообщение вы отправляете. отправка сообщений между одним процессом и другим требует соблюдения некоторых правил

DartApi: SendPort

Содержимое сообщения может быть: примитивными значениями (null, num, bool, double, String), экземплярами SendPort, а также списками и картами, элементами которых являются любые из них. Список и карты также могут быть циклическими.

Как исправить ошибку при изолировании?

Изолировать, получить один метод для прослушивания сообщения об ошибке, отправляемой изолятором: addErrorListner Это полезная функция.

НО! этот метод реализуется не во всех формах форм, поэтому вам нужно сделать это в других.

Я выбрал способ отправить 2 SendPort в функции точки входа:

  • Один для общения

  • Один за ошибку.

Итак, функция спауна выглядит так:

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

и 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()}");
      }
    });
}

Вот полный код:

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());
}
person Vink    schedule 03.07.2014
comment
А что такое c-функция? - person softshipper; 03.07.2014
comment
Невозможно использовать изолировать только на внутреннем интерфейсе, только на бэкэнде? - person softshipper; 03.07.2014
comment
Это возможно, но может быть немного сложнее - person Vink; 03.07.2014
comment
@zero_coding: приложения командной строки могут использовать Isolate.spawn(). Веб-приложения могут порождать изоляты, но должны использовать Isolate.spawnUri(). - person Argenti Apparatus; 03.08.2014