2012-09-29 41 views
8

tôi đã thiết lập một ren (với chủ đề Python) máy chủ HTTP bằng cách tạo ra một lớp kế thừa từ HTTPServer và ThreadingMixIn:chế biến đồng thời/Các yêu cầu không đồng bộ với Python BaseHTTPServer

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

Tôi có một lớp xử lý mà được thừa hưởng từ BaseHTTPRequestHandler, và tôi khởi động máy chủ với một cái gì đó như thế này:

class MyHandler(BaseHTTPRequestHandler): 
    ... 

server = ThreadedHTTPServer(('localhost', 8080), MyHandler) 
# Prevent issues with socket reuse 
server.allow_reuse_address = True 
# Start the server 
server.serve_forever() 

Đây là tất cả khá đơn giản. Vấn đề mà tôi đang gặp phải là, ThreadingMixIn, ForkingMixIn, hoặc ngược lại, yêu cầu gió lên chặn trên trình xử lý yêu cầu để trả về. Điều này có thể dễ dàng được nhìn thấy bằng cách thực hiện mã ví dụ này:

class MyHandler(BaseHTTPRequestHandler): 
    def respond(self, status_code): 
     self.send_response(status_code) 
     self.end_headers() 

    def do_GET(self): 
     print "Entered GET request handler" 
     time.sleep(10) 
     print "Sending response!" 
     respond(200) 

Nếu máy chủ đã được chế biến những loại cùng một lúc, sau đó chúng tôi sẽ có thể gửi hai yêu cầu và xem server nhập cả GET xử lý yêu cầu trước khi gửi một trong hai phản ứng. Thay vào đó, máy chủ sẽ nhập trình xử lý yêu cầu GET cho yêu cầu đầu tiên, đợi nó trả về, sau đó nhập nó cho lần thứ hai (do đó yêu cầu thứ hai mất ~ 20 giây để trả về thay vì 10).

Có cách nào đơn giản để tôi triển khai hệ thống mà máy chủ không chờ xử lý trả lại không? Cụ thể, tôi đang cố viết một hệ thống chờ đợi một vài yêu cầu trước khi trả về bất kỳ yêu cầu nào (một dạng bỏ phiếu dài) và chạy vào các vấn đề mà yêu cầu đầu tiên chờ đợi chặn bất kỳ yêu cầu nào trong tương lai kết nối với máy chủ.

Trả lời

11
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

là đủ. Khách hàng của bạn có thể không đưa ra yêu cầu đồng thời. Nếu bạn thực hiện các yêu cầu song song, máy chủ luồng hoạt động như mong đợi. Dưới đây là các khách hàng:

#!/usr/bin/env python 
import sys 
import urllib2 

from threading import Thread 

def make_request(url): 
    print urllib2.urlopen(url).read() 

def main(): 
    port = int(sys.argv[1]) if len(sys.argv) > 1 else 8000 
    for _ in range(10): 
     Thread(target=make_request, args=("http://localhost:%d" % port,)).start() 

main() 

Và máy chủ tương ứng:

import time 
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer, test as _test 
from SocketServer  import ThreadingMixIn 


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

class SlowHandler(BaseHTTPRequestHandler): 
    def do_GET(self): 
     self.send_response(200) 
     self.send_header("Content-type", "text/plain") 
     self.end_headers() 

     self.wfile.write("Entered GET request handler") 
     time.sleep(1) 
     self.wfile.write("Sending response!") 

def test(HandlerClass = SlowHandler, 
     ServerClass = ThreadedHTTPServer): 
    _test(HandlerClass, ServerClass) 


if __name__ == '__main__': 
    test() 

Tất cả 10 yêu cầu hoàn thành trong 1 giây. Nếu bạn xóa ThreadingMixIn khỏi định nghĩa máy chủ thì tất cả 10 yêu cầu mất 10 giây để hoàn tất.

+2

Tôi đã thử nghiệm điều này bằng cách gửi yêu cầu tới máy chủ thông qua Google Chrome. Hóa ra Chrome đang tuần tự hóa các yêu cầu của tôi cho cùng một máy chủ, chờ một yêu cầu quay lại trước khi gửi yêu cầu tiếp theo. Chạy một kịch bản Python đơn giản cố định nó lên. Cảm ơn! – Dylnuge

+0

Từ kinh nghiệm của tôi time.sleep (1) là không phản ánh khối lượng công việc thực tế của 1 giây vì vậy tôi không nghĩ rằng bạn nên kiểm tra độ trễ bằng cách sử dụng thread.sleep. Rất tiếc tôi không có lời giải thích chính thức nhưng tôi đoán nó có liên quan đến việc tối ưu hóa chia sẻ tài nguyên trong trường hợp của thread.sleep. – MikeL

+0

@MikeL: 'time.sleep (1)' là thích hợp cho trường hợp trong câu trả lời. Tất cả những gì chúng ta quan tâm ở đây là liệu máy chủ có thể xử lý nhiều yêu cầu đồng thời không. Như OP đã nói: vấn đề là trình duyệt không thực hiện nhiều yêu cầu đến cùng một url. – jfs