21

複数のリクエストを並行して処理できる HTTP サーバーを Dart で作成しようとしています。これまでのところ、「並列」の部分を達成することに成功していません。

最初に試したのは次のとおりです。

import 'dart:io';

main() {
  HttpServer.bind(InternetAddress.ANY_IP_V4, 8080).then((HttpServer server) {
    server.listen((HttpRequest request) {
      Stopwatch stopwatch = new Stopwatch();
      stopwatch.start();
      while (stopwatch.elapsedMilliseconds < 1000) { /* do nothing */ }
      request.response.statusCode = HttpStatus.OK;
      request.response.write(stopwatch.elapsedMilliseconds.toString());
      request.response.close().catchError(print);
    });
  });
}

リクエストごとに、ビジーな作業を 1 秒間実行してから完了します。タイミングが予測できるように、この方法でリクエストを処理するようにしました。そのため、Windows タスク マネージャーでリクエストの効果を簡単に確認できます (CPU コアが 100% 使用率にジャンプします)。

次の理由により、これはリクエストを並行して処理していないことがわかります。

  1. いくつかのブラウザー タブを読み込んでからhttp://example:8080/すべてを更新すると、タブが次々に読み込まれ、それぞれのタブが約 1 秒間隔で読み込まれます。

  2. これらの設定で 負荷テスト ツールwrkwrk -d 10 -c 8 -t 8 http://example:8080/を使用すると... ...指定した 10 秒で 5 ~ 8 件の要求が完了します。サーバーが私の 8 つのコアすべてを使用していた場合、80 に近い数のリクエストが予想されます。

  3. ワーク テスト中に Windows タスク マネージャーを開くと、使用率がほぼ 100% に近いコアは 1 つだけで、残りはほとんどアイドル状態になっていることがわかります。

そこで、リクエストごとに新しいisolate/threadを手動で生成することを期待して、isolateを使用してみました:

import 'dart:io';
import 'dart:isolate';

main() {
  HttpServer.bind(InternetAddress.ANY_IP_V4, 8080).then((HttpServer server) {
    server.listen((HttpRequest request) {
      spawnFunction(handleRequest).send(request);
    });
  });
}

handleRequest() {
  port.receive((HttpRequest request, SendPort sender) {
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.start();
    while (stopwatch.elapsedMilliseconds < 1000) { /* do nothing */ }
    request.response.statusCode = HttpStatus.OK;
    request.response.write(stopwatch.elapsedMilliseconds.toString());
    request.response.close().catchError(print);
  });
}

これはまったく機能しません。Isolate へのメッセージとして HttpRequest を送信しようとしているのは好きではありません。エラーは次のとおりです。

#0      _SendPortImpl._sendInternal (dart:isolate-patch/isolate_patch.dart:122:3)
#1      _SendPortImpl._sendNow (dart:isolate-patch/isolate_patch.dart:95:18)
#2      _SendPortImpl.send (dart:isolate-patch/isolate_patch.dart:91:18)
#3      main.<anonymous closure>.<anonymous closure> (file:///C:/Development/dartbenchmark/simple2.dart:7:40)
#4      _StreamSubscriptionImpl._sendData (dart:async/stream_impl.dart:475:12)
#5      _StreamImpl._sendData.<anonymous closure> (dart:async/stream_impl.dart:251:29)
#6      _SingleStreamImpl._forEachSubscriber (dart:async/stream_impl.dart:335:11)
#7      _StreamImpl._sendData (dart:async/stream_impl.dart:249:23)
#8      _StreamImpl._add (dart:async/stream_impl.dart:51:16)
#9      StreamController.add (dart:async/stream_controller.dart:10:35)
#10     _HttpServer._handleRequest (http_impl.dart:1261:20)
#11     _HttpConnection._HttpConnection.<anonymous closure> (http_impl.dart:1188:33)
#12     _StreamSubscriptionImpl._sendData (dart:async/stream_impl.dart:475:12)
#13     _StreamImpl._sendData.<anonymous closure> (dart:async/stream_impl.dart:251:29)
#14     _SingleStreamImpl._forEachSubscriber (dart:async/stream_impl.dart:335:11)
#15     _StreamImpl._sendData (dart:async/stream_impl.dart:249:23)
#16     _StreamImpl._add (dart:async/stream_impl.dart:51:16)
#17     StreamController.add (dart:async/stream_controller.dart:10:35)
#18     _HttpParser._doParse (http_parser.dart:415:26)
#19     _HttpParser._parse (http_parser.dart:161:15)
#20     _HttpParser._onData._onData (http_parser.dart:509:11)
#21     _StreamSubscriptionImpl._sendData (dart:async/stream_impl.dart:475:12)
#22     _StreamImpl._sendData.<anonymous closure> (dart:async/stream_impl.dart:251:29)
#23     _SingleStreamImpl._forEachSubscriber (dart:async/stream_impl.dart:335:11)
#24     _StreamImpl._sendData (dart:async/stream_impl.dart:249:23)
#25     _StreamImpl._add (dart:async/stream_impl.dart:51:16)
#26     StreamController.add (dart:async/stream_controller.dart:10:35)
#27     _Socket._onData._onData (dart:io-patch/socket_patch.dart:726:42)
#28     _StreamSubscriptionImpl._sendData (dart:async/stream_impl.dart:475:12)
#29     _StreamImpl._sendData.<anonymous closure> (dart:async/stream_impl.dart:251:29)
#30     _SingleStreamImpl._forEachSubscriber (dart:async/stream_impl.dart:335:11)
#31     _StreamImpl._sendData (dart:async/stream_impl.dart:249:23)
#32     _StreamImpl._add (dart:async/stream_impl.dart:51:16)
#33     StreamController.add (dart:async/stream_controller.dart:10:35)
#34     _RawSocket._RawSocket.<anonymous closure> (dart:io-patch/socket_patch.dart:452:52)
#35     _NativeSocket.multiplex (dart:io-patch/socket_patch.dart:253:18)
#36     _NativeSocket.connectToEventHandler.<anonymous closure> (dart:io-patch/socket_patch.dart:338:54)
#37     _ReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:81:92)

Unhandled exception:
Illegal argument(s): Illegal argument in isolate message : (object is a closure)
#0      _throwDelayed.<anonymous closure> (dart:async/stream_impl.dart:22:5)
#1      _asyncRunCallback._asyncRunCallback (dart:async/event_loop.dart:15:17)
#2      _asyncRunCallback._asyncRunCallback (dart:async/event_loop.dart:25:9)
#3      Timer.run.<anonymous closure> (dart:async/timer.dart:17:21)
#4      Timer.run.<anonymous closure> (dart:async/timer.dart:25:13)
#5      Timer.Timer.<anonymous closure> (dart:async-patch/timer_patch.dart:9:15)
#6      _Timer._createTimerHandler._handleTimeout (timer_impl.dart:99:28)
#7      _Timer._createTimerHandler._handleTimeout (timer_impl.dart:107:7)
#8      _Timer._createTimerHandler.<anonymous closure> (timer_impl.dart:115:23)
#9      _ReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:81:92)

使用したバージョン:

  • Dart Editor バージョン 0.5.9_r22879
  • Dart SDK バージョン 0.5.9.0_r22879

Dart を使用して、マシンの利用可能なすべてのコアでこれらのリクエストを並行して処理することは可能ですか?

4

3 に答える 3

9

しばらく前に、これを行うために dart-isoserver というライブラリを作成しました。今はかなり腐っていますが、参道が見えます。

https://code.google.com/p/dart-isoserver/

私がしたことは、HttpRequest と HttpResponse を分離ポート経由でプロキシすることでした。直接送信することはできないからです。いくつかの注意点がありましたが、うまくいきました。

  1. リクエストとレスポンスの I/O はメインの分離を通過したため、その部分は並列ではありませんでした。ただし、ワーカー アイソレートで行われた他の作業は、メインのアイソレートをブロックしませんでした。実際に起こるべきことは、ソケット接続がアイソレート間で転送可能であることです。
  2. アイソレートで例外が発生すると、サーバー全体がダウンします。spawnFunction()キャッチされていない例外ハンドラー パラメーターがあるため、これはある程度修正可能ですが、spawnUri() は修正できません。dart-isoserver は spawnUri() を使用してホットローディングを実装していたため、これを削除する必要がありました。
  3. Isolate は起動が少し遅く、nginx と node.js が対象とする数千の同時接続のユース ケースでは、おそらく接続ごとに 1 つは必要ありません。作業キューを備えた分離プールはおそらくパフォーマンスが向上しますが、ワーカーでブロック I/O を使用できる優れた機能が排除されます。

最初のコード例に関するメモ。お気づきのように、Dart はシングルスレッドであるため、これは間違いなく並列実行されません。同じ分離内の Dart コードが同時に実行されることはありません。

于 2013-05-23T01:18:33.467 に答える