2013-05-23 35 views
12

Tôi đang cố gắng viết máy chủ HTTP trong Dart có thể xử lý nhiều yêu cầu song song. Tôi đã không thành công trong việc đạt được phần "song song" cho đến nay.Phi tiêu: xử lý các yêu cầu HTTP đến song song

Đây là những gì tôi đã cố gắng lúc đầu:

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

Trên mỗi yêu cầu nó làm việc bận rộn trong một giây, sau đó hoàn tất. Tôi đã làm cho nó xử lý các yêu cầu theo cách này để thời gian của nó có thể dự đoán được, và vì vậy tôi có thể dễ dàng thấy hiệu ứng của yêu cầu trong trình quản lý tác vụ Windows (lõi CPU nhảy tới mức sử dụng 100%).

tôi có thể nói đây không phải là xử lý các yêu cầu song song bởi vì:

  1. Nếu tôi tải lên một vài tab trình duyệt để http://example:8080/ và sau đó làm mới tất cả, các tab tải cái khác trong chuỗi, khoảng 1 giây giữa mỗi người.

  2. Nếu tôi sử dụng công cụ kiểm tra tải wrk với các cài đặt này ... wrk -d 10 -c 8 -t 8 http://example:8080/ ... nó hoàn thành 5 đến 8 yêu cầu trong 10 giây tôi đã cung cấp. Nếu máy chủ đang sử dụng tất cả 8 lõi của tôi, tôi mong đợi một con số gần hơn 80 yêu cầu.

  3. Khi tôi mở trình quản lý tác vụ Windows trong khi kiểm tra wrk, tôi quan sát thấy chỉ một lõi của tôi là gần 100% sử dụng và phần còn lại khá nhàn rỗi.

Vì vậy, sau đó tôi cố gắng sử dụng phân lập, hy vọng tự đẻ trứng một chủng mới/chủ đề cho mỗi yêu cầu:

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

này không làm việc ở tất cả. Nó không giống như tôi đang cố gắng gửi một HttpRequest như tin nhắn cho cô lập. Dưới đây là các lỗi:

#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) 

phiên bản sử dụng: Phiên bản

  • Dart Editor phiên bản 0.5.9_r22879
  • Dart SDK 0.5.9.0_r22879

Có thể để xử lý các yêu cầu song song, với tất cả lõi có sẵn của máy tính của tôi, sử dụng Dart?

Trả lời

9

Tôi đã viết một thư viện có tên là dart-isoserver để thực hiện việc này trong khi quay lại. Bây giờ nó đã bị hỏng một chút, nhưng bạn có thể thấy cách tiếp cận này.

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

Những gì tôi đã làm là Proxy HttpRequest và HttpResponse qua cổng cô lập, vì bạn không thể gửi chúng trực tiếp. Nó đã hoạt động, mặc dù có một vài cảnh báo:

  1. I/O theo yêu cầu và phản hồi mặc dù cô lập chính, do đó phần đó không song song. Các công việc khác được thực hiện trong công nhân cô lập đã không ngăn chặn các cô lập chính mặc dù. Điều thực sự nên xảy ra là một kết nối socket nên được chuyển giao giữa các phân lập.
  2. Trường hợp ngoại lệ trong cách ly sẽ làm hỏng toàn bộ máy chủ.spawnFunction() hiện có một tham số xử lý ngoại lệ chưa được nắm bắt, do đó, điều này có phần có thể khắc phục được, nhưng spawnUri() thì không. dart-isoserver sử dụng spawnUri() để thực hiện tải nóng, do đó sẽ phải được loại bỏ.
  3. Các cách ly có chút chậm để khởi động và có thể bạn không muốn một kết nối cho mỗi nghìn trường hợp sử dụng kết nối đồng thời mà mục tiêu nginx và node.js nhắm mục tiêu. Một hồ bơi cô lập với hàng đợi công việc có thể sẽ hoạt động tốt hơn, mặc dù điều đó sẽ loại bỏ tính năng đẹp mà bạn có thể sử dụng chặn I/O trong một nhân viên.

Lưu ý về ví dụ mã đầu tiên của bạn. Điều đó chắc chắn sẽ không chạy song song, như bạn nhận thấy, bởi vì Dart là đơn luồng. Không có mã phi tiêu nào trong cùng một phân đoạn chạy đồng thời.

+0

Cảm ơn. Điều này nói với tôi rằng tôi không bỏ lỡ điều gì hiển nhiên, và câu trả lời cho câu hỏi ban đầu của tôi về cơ bản là, "Không." chỉnh sửa: Rất tiếc, tôi đã gửi quá sớm một cách tình cờ. Tôi đã tìm thấy [vấn đề này] (https://code.google.com/p/dart/issues/detail?id=5006) trên trình theo dõi của họ nghe có vẻ giống như những gì tôi muốn. Rõ ràng họ tập trung nhiều hơn vào vấn đề cấp độ ngôn ngữ và phía khách hàng ngay bây giờ, và ít lo lắng về những thứ phía máy chủ như thế này ... điều đó là tốt. Hiệu suất của máy chủ đơn luồng không phải là khủng khiếp miễn là bạn chỉ so sánh nó với đường ray và khung công tác PHP. –

6

Ngay cả với giới hạn HttpServer hiện tại, có thể sử dụng nhiều lõi bằng cách chạy nhiều quy trình máy chủ phía sau máy chủ proxy ngược như Apache hoặc Nginx. Từ bên trong Dart, bạn cũng có thể chia các quy trình con để tách ra các nhiệm vụ tính toán chuyên sâu.

Một nơi tốt để bắt đầu sẽ là đọc về việc chia tỷ lệ node.js, vì điều này cũng sử dụng một cấu trúc từng luồng cho mỗi quy trình.

Chỉnh sửa: Câu trả lời giờ đã lỗi thời, giờ đây bạn có thể chia sẻ các yêu cầu giữa các phân lập cho phép quy trình Dart sử dụng nhiều lõi.

Xem tài liệu cho ServerSocket.bind(shared).

"Đối số tùy chọn được chia sẻ chỉ định liệu các liên kết bổ sung vào cùng một địa chỉ, cổng và v6Chỉ kết hợp có thể thực hiện được từ cùng một quy trình Dart hay không. của ServerSockets. Một cách để sử dụng điều này là có số lượng phân lập giữa các kết nối đến được phân phối. "

Các vấn đề liên quan