flask 다 중 스 레 드 를 여 는 구체 적 인 방법
이번 에는 플 라 스 크 가 다 중 스 레 드 를 어떻게 켜 는 지 말씀 드 리 겠 습 니 다.
app.run()이라는 방법 부터 볼 게 요.
def run(self, host=None, port=None, debug=None, **options):
from werkzeug.serving import run_simple
if host is None:
host = '127.0.0.1'
if port is None:
server_name = self.config['SERVER_NAME']
if server_name and ':' in server_name:
port = int(server_name.rsplit(':', 1)[1])
else:
port = 5000
if debug is not None:
self.debug = bool(debug)
options.setdefault('use_reloader', self.debug)
options.setdefault('use_debugger', self.debug)
try:
run_simple(host, port, self, **options) #
finally:
# reset the first request information if the development server
# reset normally. This makes it possible to restart the server
# without reloader and that stuff from an interactive shell.
self._got_first_request = False
판단 및 설정 후 run 입장simple()이 함수,원본 코드 보 세 요.def run_simple(hostname, port, application, use_reloader=False,
use_debugger=False, use_evalex=True,
extra_files=None, reloader_interval=1,
reloader_type='auto', threaded=False,
processes=1, request_handler=None, static_files=None,
passthrough_errors=False, ssl_context=None):
"""Start a WSGI application. Optional features include a reloader,
multithreading and fork support.
This function has a command-line interface too::
python -m werkzeug.serving --help
.. versionadded:: 0.5
`static_files` was added to simplify serving of static files as well
as `passthrough_errors`.
.. versionadded:: 0.6
support for SSL was added.
.. versionadded:: 0.8
Added support for automatically loading a SSL context from certificate
file and private key.
.. versionadded:: 0.9
Added command-line interface.
.. versionadded:: 0.10
Improved the reloader and added support for changing the backend
through the `reloader_type` parameter. See :ref:`reloader`
for more information.
:param hostname: The host for the application. eg: ``'localhost'``
:param port: The port for the server. eg: ``8080``
:param application: the WSGI application to execute
:param use_reloader: should the server automatically restart the python
process if modules were changed?
:param use_debugger: should the werkzeug debugging system be used?
:param use_evalex: should the exception evaluation feature be enabled?
:param extra_files: a list of files the reloader should watch
additionally to the modules. For example configuration
files.
:param reloader_interval: the interval for the reloader in seconds.
:param reloader_type: the type of reloader to use. The default is
auto detection. Valid values are ``'stat'`` and
``'watchdog'``. See :ref:`reloader` for more
information.
:param threaded: should the process handle each request in a separate
thread?
:param processes: if greater than 1 then handle each request in a new process
up to this maximum number of concurrent processes.
:param request_handler: optional parameter that can be used to replace
the default one. You can use this to replace it
with a different
:class:`~BaseHTTPServer.BaseHTTPRequestHandler`
subclass.
:param static_files: a list or dict of paths for static files. This works
exactly like :class:`SharedDataMiddleware`, it's actually
just wrapping the application in that middleware before
serving.
:param passthrough_errors: set this to `True` to disable the error catching.
This means that the server will die on errors but
it can be useful to hook debuggers in (pdb etc.)
:param ssl_context: an SSL context for the connection. Either an
:class:`ssl.SSLContext`, a tuple in the form
``(cert_file, pkey_file)``, the string ``'adhoc'`` if
the server should automatically create one, or ``None``
to disable SSL (which is the default).
"""
if not isinstance(port, int):
raise TypeError('port must be an integer')
if use_debugger:
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(application, use_evalex)
if static_files:
from werkzeug.wsgi import SharedDataMiddleware
application = SharedDataMiddleware(application, static_files)
def log_startup(sock):
display_hostname = hostname not in ('', '*') and hostname or 'localhost'
if ':' in display_hostname:
display_hostname = '[%s]' % display_hostname
quit_msg = '(Press CTRL+C to quit)'
port = sock.getsockname()[1]
_log('info', ' * Running on %s://%s:%d/ %s',
ssl_context is None and 'http' or 'https',
display_hostname, port, quit_msg)
def inner():
try:
fd = int(os.environ['WERKZEUG_SERVER_FD'])
except (LookupError, ValueError):
fd = None
srv = make_server(hostname, port, application, threaded,
processes, request_handler,
passthrough_errors, ssl_context,
fd=fd)
if fd is None:
log_startup(srv.socket)
srv.serve_forever()
if use_reloader:
# If we're not running already in the subprocess that is the
# reloader we want to open up a socket early to make sure the
# port is actually available.
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
if port == 0 and not can_open_by_fd:
raise ValueError('Cannot bind to a random port with enabled '
'reloader if the Python interpreter does '
'not support socket opening by fd.')
# Create and destroy a socket so that any exceptions are
# raised before we spawn a separate Python interpreter and
# lose this ability.
address_family = select_ip_version(hostname, port)
s = socket.socket(address_family, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(get_sockaddr(hostname, port, address_family))
if hasattr(s, 'set_inheritable'):
s.set_inheritable(True)
# If we can open the socket by file descriptor, then we can just
# reuse this one and our socket will survive the restarts.
if can_open_by_fd:
os.environ['WERKZEUG_SERVER_FD'] = str(s.fileno())
s.listen(LISTEN_QUEUE)
log_startup(s)
else:
s.close()
# Do not use relative imports, otherwise "python -m werkzeug.serving"
# breaks.
from werkzeug._reloader import run_with_reloader
run_with_reloader(inner, extra_files, reloader_interval,
reloader_type)
else:
inner() #
판단 및 설정 후 run 입장simple()이 함수,원본 코드 보 세 요.def run_simple(hostname, port, application, use_reloader=False,
use_debugger=False, use_evalex=True,
extra_files=None, reloader_interval=1,
reloader_type='auto', threaded=False,
processes=1, request_handler=None, static_files=None,
passthrough_errors=False, ssl_context=None):
"""Start a WSGI application. Optional features include a reloader,
multithreading and fork support.
This function has a command-line interface too::
python -m werkzeug.serving --help
.. versionadded:: 0.5
`static_files` was added to simplify serving of static files as well
as `passthrough_errors`.
.. versionadded:: 0.6
support for SSL was added.
.. versionadded:: 0.8
Added support for automatically loading a SSL context from certificate
file and private key.
.. versionadded:: 0.9
Added command-line interface.
.. versionadded:: 0.10
Improved the reloader and added support for changing the backend
through the `reloader_type` parameter. See :ref:`reloader`
for more information.
:param hostname: The host for the application. eg: ``'localhost'``
:param port: The port for the server. eg: ``8080``
:param application: the WSGI application to execute
:param use_reloader: should the server automatically restart the python
process if modules were changed?
:param use_debugger: should the werkzeug debugging system be used?
:param use_evalex: should the exception evaluation feature be enabled?
:param extra_files: a list of files the reloader should watch
additionally to the modules. For example configuration
files.
:param reloader_interval: the interval for the reloader in seconds.
:param reloader_type: the type of reloader to use. The default is
auto detection. Valid values are ``'stat'`` and
``'watchdog'``. See :ref:`reloader` for more
information.
:param threaded: should the process handle each request in a separate
thread?
:param processes: if greater than 1 then handle each request in a new process
up to this maximum number of concurrent processes.
:param request_handler: optional parameter that can be used to replace
the default one. You can use this to replace it
with a different
:class:`~BaseHTTPServer.BaseHTTPRequestHandler`
subclass.
:param static_files: a list or dict of paths for static files. This works
exactly like :class:`SharedDataMiddleware`, it's actually
just wrapping the application in that middleware before
serving.
:param passthrough_errors: set this to `True` to disable the error catching.
This means that the server will die on errors but
it can be useful to hook debuggers in (pdb etc.)
:param ssl_context: an SSL context for the connection. Either an
:class:`ssl.SSLContext`, a tuple in the form
``(cert_file, pkey_file)``, the string ``'adhoc'`` if
the server should automatically create one, or ``None``
to disable SSL (which is the default).
"""
if not isinstance(port, int):
raise TypeError('port must be an integer')
if use_debugger:
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(application, use_evalex)
if static_files:
from werkzeug.wsgi import SharedDataMiddleware
application = SharedDataMiddleware(application, static_files)
def log_startup(sock):
display_hostname = hostname not in ('', '*') and hostname or 'localhost'
if ':' in display_hostname:
display_hostname = '[%s]' % display_hostname
quit_msg = '(Press CTRL+C to quit)'
port = sock.getsockname()[1]
_log('info', ' * Running on %s://%s:%d/ %s',
ssl_context is None and 'http' or 'https',
display_hostname, port, quit_msg)
def inner():
try:
fd = int(os.environ['WERKZEUG_SERVER_FD'])
except (LookupError, ValueError):
fd = None
srv = make_server(hostname, port, application, threaded,
processes, request_handler,
passthrough_errors, ssl_context,
fd=fd)
if fd is None:
log_startup(srv.socket)
srv.serve_forever()
if use_reloader:
# If we're not running already in the subprocess that is the
# reloader we want to open up a socket early to make sure the
# port is actually available.
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
if port == 0 and not can_open_by_fd:
raise ValueError('Cannot bind to a random port with enabled '
'reloader if the Python interpreter does '
'not support socket opening by fd.')
# Create and destroy a socket so that any exceptions are
# raised before we spawn a separate Python interpreter and
# lose this ability.
address_family = select_ip_version(hostname, port)
s = socket.socket(address_family, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(get_sockaddr(hostname, port, address_family))
if hasattr(s, 'set_inheritable'):
s.set_inheritable(True)
# If we can open the socket by file descriptor, then we can just
# reuse this one and our socket will survive the restarts.
if can_open_by_fd:
os.environ['WERKZEUG_SERVER_FD'] = str(s.fileno())
s.listen(LISTEN_QUEUE)
log_startup(s)
else:
s.close()
# Do not use relative imports, otherwise "python -m werkzeug.serving"
# breaks.
from werkzeug._reloader import run_with_reloader
run_with_reloader(inner, extra_files, reloader_interval,
reloader_type)
else:
inner() #
아니면 일련의 판단 을 거 친 후에 기본적으로 inner()함수 에 들 어 갑 니 다.이 함 수 는 run 로 정 의 됩 니 다.simple()내,클 라 이언 트 에 속 하 며,inner()에 서 는 make 를 실행 합 니 다.server()이 함수,원본 코드 보기:def make_server(host=None, port=None, app=None, threaded=False, processes=1,
request_handler=None, passthrough_errors=False,
ssl_context=None, fd=None):
"""Create a new server instance that is either threaded, or forks
or just processes one request after another.
"""
if threaded and processes > 1:
raise ValueError("cannot have a multithreaded and "
"multi process server.")
elif threaded:
return ThreadedWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context, fd=fd)
elif processes > 1:
return ForkingWSGIServer(host, port, app, processes, request_handler,
passthrough_errors, ssl_context, fd=fd)
else:
return BaseWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context, fd=fd)
이 를 보면 알 수 있 습 니 다.다 중 스 레 드 나 다 중 프로 세 스 를 설정 하려 면 threaded 나 processes 라 는 두 개의 인 자 를 설정 해 야 합 니 다.이 두 개의 인 자 는 app.run()에서 전 달 된 것 입 니 다.app.run(**options) ---> run_simple(threaded,processes) ---> make_server(threaded,processes)
기본 적 인 상황 에서 fllask 는 단일 스 레 드 입 니 다.단일 프로 세 스 를 시작 하려 면 run 에서 해당 하 는 매개 변 수 를 입력 하 십시오:app.run(threaded=True)하면 됩 니 다.
Make 에서server 에서 알 수 있 듯 이 flask 는 세 가지 서버 를 제공 합 니 다.Threaded WSGIServer,Forking WSGIServer,BaseWSGIServer,기본 값 은 BaseWSGIServer 입 니 다.
스 레 드 를 예 로 들 면 ThreadedWSGIServer 와 같은 종 류 를 보십시오.
class ThreadedWSGIServer(ThreadingMixIn,BaseWSGIServer):\#ThreadingMixIn,BaseWSGIServer 에서 계승
"""A WSGI server that does threading."""
multithread = True
daemon_threads = True
ThreadingMixIn = socketserver.ThreadingMixInclass ThreadingMixIn:
"""Mix-in class to handle each request in a new thread."""
# Decides how threads will act upon termination of the
# main process
daemon_threads = False
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
In addition, exception handling is done here.
"""
try:
self.finish_request(request, client_address)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
self.shutdown_request(request)
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
t.start()
process_request 는 모든 요청 에 새로운 스 레 드 를 만들어 처리 하 는 것 입 니 다.마지막 으로 상기 표현 을 검증 하기 위해 매우 간단 한 응용 프로그램 을 쓰 십시오.
from flask import Flask
from flask import _request_ctx_stack
app = Flask(__name__)
@app.route('/')
def index():
print(_request_ctx_stack._local.__ident_func__())
while True:
pass
return '<h1>hello</h1>'
app.run()\#다 중 스 레 드 를 열 려 면 app.run(threaded=True)_request_ctx_stack._local.__ident_func__()대응 하 는 getident()이 함 수 는 현재 스 레 드 id 로 돌아 갑 니 다.왜 뒤에 while True 라 는 말 을 붙 입 니까?get 을 봅 시다.ident()이 함수 에 대한 설명:
Return a non-zero integer that uniquely identifies the current thread amongst other threads that exist simultaneously. This may be used to identify per-thread resources. Even though on some platforms threads identities may appear to be allocated consecutive numbers starting at 1, this behavior should not be relied upon, and the number should be seen purely as a magic cookie. A thread's identity may be reused for another thread after it exits.
키 워드 는 제 가 굵 어 졌 습 니 다.스 레 드 id 는 스 레 드 가 끝 난 후에 반복 적 으로 이용 할 것 입 니 다.그래서 저 는 경로 함수 에 이 순환 을 추가 하여 서로 다른 id 를 관찰 할 수 있 도록 요청 을 막 았 습 니 다.그러면 두 가지 상황 이 발생 할 것 입 니 다.
1.다 중 스 레 드 를 켜 지 않 은 상태 에서 한 번 의 요청 이 오 면 서버 가 직접 차단 되 고 그 후의 다른 요청 도 모두 차단 된다.
2.다 중 스 레 드 를 켜 면 매번 다른 스 레 드 id 를 출력 합 니 다.
결과:
제1 종 상황
Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
139623180527360
두 번 째 상황
Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
140315469436672
140315477829376
140315486222080
140315316901632
140315105163008
140315096770304
140315088377600
결과 가 뻔 하 다
다시 말하자면 flask 는 다 중 스 레 드 를 지원 하지만 기본적으로 켜 지지 않 았 습 니 다.그 다음 에 app.run()은 개발 환경 에 만 적 용 됩 니 다.생산 환경 에서 uwSGI,Gunicorn 등 웹 서버 를 사용 할 수 있 습 니 다.
내용 확장:
flask 다 중 스 레 드 를 시작 하 시 겠 습 니까?다 중 프로 세 스 를 시작 하 시 겠 습 니까?
Flask 기본 값 은 단일 프로 세 스 입 니 다.단일 스 레 드 가 막 힌 작업 모드 입 니 다.프로젝트 가 실 행 될 때 nginx+gunicorn 방식 으로 flask 작업 을 배치 할 수 있 습 니 다.
하지만 개발 과정 에서 지연 되 는 방식 으로 높 은 병발 을 테스트 하려 면 어떻게 해 야 할 까?간단 하 다.
app.run()에 서 는 threaded 와 processes 두 개의 인 자 를 받 아들 일 수 있 습 니 다.스 레 드 지원 과 프로 세 스 지원 을 시작 하 는 데 사 용 됩 니 다.
1.threaded:다 중 스 레 드 지원,기본 값 은 False,즉 다 중 스 레 드 를 열지 않 습 니 다.
2.processes:프로 세 스 수량,기본 값 은 1 입 니 다.
오픈 방식:
if __name__ == '__main__':
app.run(threaded=True)
# app.run(processes=4)
메모:다 중 프로 세 스 나 다 중 스 레 드 는 하나만 선택 할 수 있 고 동시에 열 수 없습니다.이상 은 fllask 가 다 중 스 레 드 를 여 는 구체 적 인 방법 에 대한 상세 한 내용 입 니 다.fllask 가 다 중 스 레 드 를 어떻게 여 는 지 에 대한 상세 한 자 료 는 저희 의 다른 관련 글 을 주목 하 시기 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
(동영상) Flask API 생성기 및 보기 - 무료 제품이 문서에서 언급한 비디오 자료는 항목을 추가, 편집 및 제거할 수 있는 간단한 페이지인 API 보기를 사용하여 Flask 생성 API와 상호 작용하는 방법을 설명합니다. 이 기능으로 향상된 제품 은 Github에서...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.