2012-11-12 7 views
1

Python에서 정적 파일을 제공하는 가장 빠른 방법은 무엇입니까? Nginx의 정적 파일 제공과 동등하거나 가까운 것을 찾고 있습니다.Python 빠른 정적 파일 제공

저는 SimpleHTTPServer에 대해 알고 있지만 여러 파일을 효율적이고 안정적으로 처리 할 수 ​​있는지 여부는 확신 할 수 없습니다.

또한 lib/framework가 경량 인 한 일종의 lib/framework의 일부가 될 필요는 없습니다.

+1

이것은 실제로 파이썬에 대한 직업이 아닙니다. Nginx의 문제점은 무엇입니까? –

+0

@DanielRoseman : Ngix가 Python 응용 프로그램으로 패키지하고 배포하는 것이 덜 실용적이라고 상상할 수 있습니다. – Hubro

+0

@DanielRoseman 나는 파이썬 기반의 가볍고 가능한 한 효율적인 것을 필요로하기 때문에. 작은 패키지를 쓰고 있는데 Nginx와 같은 외부 종속성에 의존하지 않고 정적 파일 제공을 번들로 제공하고 싶습니다. – Marconi

답변

3

FAPWS3? 판매 포인트 중 하나

정적 파일 서버

FAPWS 정적 파일 요청의 엄청난 금액을 제공하는 데 사용할 수 있습니다

. 백엔드에있는 비동기 데이터베이스의 도움으로 FAPWS를 자신의 Amazon S3로 사용할 수 있습니다.

+0

그래, 이걸 보았고 실제로 고려해 보았을거야. 내가 물어 본 이유가 더 많은 인풋이 필요합니다. – Marconi

1

제 3 자 HTTP 서버를 사용하여 정적 파일을 제공하는 것이 좋습니다.

nginx와 같은 서버는 빠른 작업 언어로 병렬화되고 작성된 작업에 집중적으로 사용됩니다.

파이썬이 하나의 프로세서에 연결되어 있고 해석됩니다.

+0

>가 해석됩니다. Doss't 문제가 많습니다. 파일 서비스는 IOBound입니다. –

+0

'파이썬이 하나의 프로세서에 묶여있다 ' 결코 하나의 프로세서에 묶여 있지 않다. 스레딩에서 GIL 만 잠급니다. Python mutliprocessing 표준 라이브러리와 많은 병렬 처리 타사 라이브러리가 스레딩보다 우수하며 모든 것이 다중 프로세서에서 작동합니다. –

-1

당신이 oneliner 찾는 경우에 당신은 다음을 수행 할 수

$> 파이썬 -m SimpleHTTPServer

이 모든 작업이 필요 fullfil되지 않지만 가치가이 이라고 언급을 가장 간단한 방법 :-)

+0

SimpleHTTPServer에 대해 알고 있습니다. :) – Marconi

+0

자기 소개 : 먼저 질문을 읽어보십시오 :-) – kiddouk

0

원본 SimpleHTTPServer 파이썬 표준 라이브러리에서 "은 여러 파일을 효율적이고 안정적으로 처리합니다. ". 예를 들어, 하나의 파일을 다운로드하는 경우 SimpleHTTPServer.py인 단순 싱글 스레드 HTTP 서버은 동시에 하나만 연결하면을 지원할 수 있기 때문에 다른 HTTP 액세스가 있어야합니다. 다행히

은 또한 파이썬 표준 라이브러리에서 SocketServer.ForkingMixInSocketServer.ThreadingMixIn 래핑 할 수 SimpleHTTPServer.py 사용 핸들러로 BaseHTTPServer.HTTPServer는 매우 간단한 HTTP 서버의 "이용 효율과 신뢰성을 향상시킬 수있는 멀티 프로세스, 멀티 스레드 모드를 지원하기 위해 참고 ".

는이 아이디어에 따르면,로 주어진다 원래 하나에서 수정 된 멀티 스레드/멀티 프로세스 지원와 SimpleHTTPServer은 다음과 같습니다 예를 들어

$ python2.7 ModifiedSimpleHTTPServer.py 
usage: ModifiedSimpleHTTPServer.py [-h] [--pydoc] [--port PORT] 
            [--type {process,thread}] [--root ROOT] 
            [--run] 

Modified SimpleHTTPServer with MultiThread/MultiProcess and IP bind support. 

Original: https://docs.python.org/2.7/library/simplehttpserver.html 
Modified by: [email protected] 

optional arguments: 
    -h, --help   show this help message and exit 
    --pydoc    show this module's pydoc 

run arguments: 

    --port PORT   specify server port (default: 8000) 
    --type {process,thread} 
         specify server type (default: 'thread') 
    --root ROOT   specify root directory (default: cwd '/home/vbem') 
    --run     run http server foreground 

NOTE: stdin for input, stdout for result, stderr for logging 

, ModifiedSimpleHTTPServer.py --run --root /var/log --type process 정적 멀티 프로세스 HTTP를 실행합니다 '/ var/log'를 루트 디렉토리로 사용하는 파일 서버입니다.

수정 된 코드는 다음과 같습니다

#! /usr/bin/env python2.7 
# -*- coding: utf-8 -*- 
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
r"""Modified SimpleHTTPServer with MultiThread/MultiProcess and IP bind support. 

Original: https://docs.python.org/2.7/library/simplehttpserver.html 
Modified by: [email protected] 
""" 

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
import os, sys, pwd, posixpath, BaseHTTPServer, urllib, cgi, shutil, mimetypes, socket, SocketServer, BaseHTTPServer 
from cStringIO import StringIO 

USERNAME = pwd.getpwuid(os.getuid()).pw_name 
HOSTNAME = socket.gethostname() 
PORT_DFT = 8000 

class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 

    server_version = "SimpleHTTP/0.6" 

    def do_GET(self): 
     f = self.send_head() 
     if f: 
      self.copyfile(f, self.wfile) 
      f.close() 

    def do_HEAD(self): 
     f = self.send_head() 
     if f: 
      f.close() 

    def send_head(self): 
     path = self.translate_path(self.path) 
     f = None 
     if os.path.isdir(path): 
      if not self.path.endswith('/'): 
       self.send_response(301) 
       self.send_header("Location", self.path + "/") 
       self.end_headers() 
       return None 
      for index in "index.html", "index.htm": 
       index = os.path.join(path, index) 
       if os.path.exists(index): 
        path = index 
        break 
      else: 
       return self.list_directory(path) 
     ctype = self.guess_type(path) 
     try: 
      f = open(path, 'rb') 
     except IOError: 
      self.send_error(404, "File not found") 
      return None 
     self.send_response(200) 
     self.send_header("Content-type", ctype) 
     fs = os.fstat(f.fileno()) 
     self.send_header("Content-Length", str(fs[6])) 
     self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) 
     self.end_headers() 
     return f 

    def list_directory(self, path): 
     try: 
      list = ['..'] + os.listdir(path) # 
     except os.error: 
      self.send_error(404, "No permission to list directory") 
      return None 
     list.sort(key=lambda a: a.lower()) 
     f = StringIO() 
     displaypath = cgi.escape(urllib.unquote(self.path)) 
     f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">') 
     f.write("<html>\n<title>%s %s</title>\n<body>" % (HOSTNAME, displaypath)) 
     f.write("%[email protected]%s:<strong>%s</strong>\n" % (USERNAME, HOSTNAME, path.rstrip('/')+'/')) 
     f.write("<hr>\n<ul>\n") 
     for name in list: 
      fullname = os.path.join(path, name) 
      displayname = linkname = name 
      if os.path.isdir(fullname): 
       displayname = name + "/" 
       linkname = name + "/" 
      if os.path.islink(fullname): 
       displayname = name + "@" 
      f.write('<li><a href="%s">%s</a>\n' 
        % (urllib.quote(linkname), cgi.escape(displayname))) 
     f.write("</ul>\n<hr>\n<pre>%s</pre>\n</body>\n</html>\n" % __doc__) 
     length = f.tell() 
     f.seek(0) 
     self.send_response(200) 
     encoding = sys.getfilesystemencoding() 
     self.send_header("Content-type", "text/html; charset=%s" % encoding) 
     self.send_header("Content-Length", str(length)) 
     self.end_headers() 
     return f 

    def translate_path(self, path): 
     path = path.split('?',1)[0] 
     path = path.split('#',1)[0] 
     path = posixpath.normpath(urllib.unquote(path)) 
     words = path.split('/') 
     words = filter(None, words) 
     path = os.getcwd() 
     for word in words: 
      drive, word = os.path.splitdrive(word) 
      head, word = os.path.split(word) 
      if word in (os.curdir, os.pardir): continue 
      path = os.path.join(path, word) 
     return path 

    def copyfile(self, source, outputfile): 
     shutil.copyfileobj(source, outputfile) 

    def guess_type(self, path): 
     base, ext = posixpath.splitext(path) 
     if ext in self.extensions_map: 
      return self.extensions_map[ext] 
     ext = ext.lower() 
     if ext in self.extensions_map: 
      return self.extensions_map[ext] 
     else: 
      return self.extensions_map[''] 

    if not mimetypes.inited: 
     mimetypes.init() 
    extensions_map = mimetypes.types_map.copy() 
    extensions_map.update({'': 'text/plain'}) 

class ProcessedHTTPServer(SocketServer.ForkingMixIn, BaseHTTPServer.HTTPServer): 
    r"""Handle requests in multi process.""" 

class ThreadedHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): 
    r"""Handle requests in a separate thread.""" 

SERVER_DICT = { 
    'thread' : ThreadedHTTPServer, 
    'process' : ProcessedHTTPServer, 
} 
SERVER_DFT = 'thread' 

def run(sCwd=None, sServer=SERVER_DFT, nPort=PORT_DFT, *lArgs, **dArgs): 
    r""" 
    """ 
    sys.stderr.write('start with %r\n' % sys._getframe().f_locals) 
    if sCwd is not None: 
     os.chdir(sCwd) 
    cServer = SERVER_DICT[sServer] 
    oHttpd = cServer(("", nPort), SimpleHTTPRequestHandler) 
    sys.stderr.write('http://%s:%s/\n' % (HOSTNAME, nPort)) 
    oHttpd.serve_forever() 

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
# main 

def _main(): 
    r"""Main. 
    """ 
    import argparse 

    oParser = argparse.ArgumentParser(
     description = __doc__, 
     formatter_class = argparse.RawTextHelpFormatter, 
     epilog = 'NOTE: stdin for input, stdout for result, stderr for logging', 
    ) 
    oParser.add_argument('--pydoc', action='store_true', 
     help = "show this module's pydoc", 
    ) 

    oGroupR = oParser.add_argument_group(title='run arguments', description='') 
    oGroupR.add_argument('--port', action='store', type=int, default=PORT_DFT, 
     help = 'specify server port (default: %(default)r)', 
    ) 
    oGroupR.add_argument('--type', action='store', default=SERVER_DFT, choices=SERVER_DICT.keys(), 
     help = 'specify server type (default: %(default)r)', 
    ) 
    oGroupR.add_argument('--root', action='store', default=os.getcwd(), 
     help = 'specify root directory (default: cwd %(default)r)', 
    ) 
    oGroupR.add_argument('--run', action='store_true', 
     help = '\n'.join((
      'run http server foreground', 
    ))) 

    oArgs = oParser.parse_args() 

    if oArgs.pydoc: 
     help(os.path.splitext(os.path.basename(__file__))[0]) 
    elif oArgs.run: 
     return run(sCwd=oArgs.root, sServer=oArgs.type, nPort=oArgs.port) 
    else: 
     oParser.print_help() 
     return 1 

    return 0 

if __name__ == "__main__": 
    exit(_main()) 

한편, 200 선으로 하나의 파이썬 파일은 "파이썬에 "와 "경량"요구를 충족 할 수 있습니다.

마지막으로,이 ModifiedSimpleHTTPServer.py은 일시적인 사용을 위해 손으로 "킬러 응용 프로그램"일 수 있지만 Nginx는 장기간 사용하도록 권장됩니다.

관련 문제