2012-09-29 13 views
8

による処理の同時/非同期リクエスト:私はHTTPServerのとThreadingMixInから継承したクラスを作成することによって、(Pythonのスレッドで)ネジ付きHTTPサーバを設定しているPythonのBaseHTTPServer

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

私が継承するハンドラクラスを持っていますBaseHTTPRequestHandlerではから、私はこのようなものを使用してサーバを起動します。

class MyHandler(BaseHTTPRequestHandler): 
    ... 

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

これは、すべての非常に簡単です。私が遭遇している問題は、ThreadingMixIn、ForkingMixIn、またはそうでなければ、要求は戻るために要求ハンドラ上でブロックされます。これは、簡単にこの例のコードを実装することで見ることができます。

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) 

サーバが同時にこれらを処理した場合、我々は2つの要求を送信し、サーバの両方がどちらかの応答を送信する前に要求ハンドラをGET入る見ることができるでしょう。代わりに、サーバーは最初の要求のGET要求ハンドラーに入り、それが戻ってから2番目の要求を入力します(したがって、2番目の要求は10秒ではなく20秒戻ります)。

サーバがハンドラを返すのを待たないシステムを実装する簡単な方法はありますか?具体的には、いくつかのリクエストを受け取るのを待つシステム(長いポーリングの1つ)を返す前に、最初のリクエストが将来のリクエストがサーバへの接続をブロックする問題に走るシステムを作成しようとしています。

答えて

11
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): 
    pass 

で十分です。あなたのクライアントはおそらく同時要求をしません。パラレルで要求を行うと、スレッドサーバーは期待どおりに動作します。

#!/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() 

と、対応するサーバー:ここではクライアントです

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

すべての10の要求は、1秒で終了します。サーバー定義からThreadingMixInを除去すると、10個の要求すべてが完了するのに10秒かかります。

+2

Google Chromeを使用してサーバーにリクエストを送信してテストしていました。 Chromeは自分のリクエストを同じサーバにシリアライズしていましたが、次のリクエストを送信する前に返信するのを待っていました。シンプルなPythonスクリプトを実行すると修正されました。ありがとう! – Dylnuge

+0

私の経験から、sleep.sleep(1)は実際の作業負荷を1秒間反映していないので、thread.sleepを使ってレイテンシをテストする必要はありません。残念ながら正式な説明はありませんが、thread.sleepの場合はリソース共有の最適化と関係があると推測しています。 – MikeL

+0

@MikeL: 'time.sleep(1)'は答えの場合に適しています。ここで興味深いのは、サーバーが複数の同時要求をまったく処理できるかどうかだけです。 OPが言ったように:問題は、ブラウザが同じURLへの複数のリクエストをしないということでした。 – jfs

関連する問題