8

我正在尝试使用 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)

结论我的问题:

如何将变量传递给隔离上的调用方法?
如何处理隔离错误?

4

1 回答 1

18

首先,

隔离不是线程,它们是独立的进程,更像是一个fork()而不是一个线程

dartApi:隔离

使用隔离的并发编程:类似于线程但不共享内存的独立工作者,仅通过消息进行通信。

因此,您无法访问与父进程相同的变量。这是 dart 团队做出的选择,因为它是在 js 中编译 dart 代码时可用的机制。所以在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:发送端口

消息的内容可以是:原始值(null、num、bool、double、String)、SendPort 的实例以及元素为这些中的任何一个的列表和映射。列表和映射也可以是循环的。

如何处理隔离错误?

Isolate 获取一个监听由isolate 发送的抛出错误的方法:addErrorListner 这是一个有用的函数。

但 !此方法并非在每个版式中都实现,因此您需要在其他版中执行此操作。

我选择的方式是在入口点函数中发送 2 SendPort:

  • 一个用于通讯

  • 一为错误。

所以 spawn 函数看起来像:

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());
}
于 2014-07-03T13:20:00.137 回答