Сервер Gevent Pywsgi — многопроцессорность?

Следующий код (взято отсюда: https://bitbucket.org/denis/gevent/src/6c710e8ae58b/examples/wsgiserver_ssl.py) реализует чрезвычайно быстрый веб-сервер wsgi на базе Greenlet:

#!/usr/bin/python
"""Secure WSGI server example based on gevent.pywsgi"""

from gevent import pywsgi


def hello_world(env, start_response):
    if env['PATH_INFO'] == '/':
        start_response('200 OK', [('Content-Type', 'text/html')])
        return ["<b>hello world</b>"]
    else:
        start_response('404 Not Found', [('Content-Type', 'text/html')])
        return ['<h1>Not Found</h1>']

print 'Serving on https://127.0.0.1:8443'
server = pywsgi.WSGIServer(('0.0.0.0', 8443), hello_world, keyfile='server.key', certfile='server.crt')
# to start the server asynchronously, call server.start()
# we use blocking serve_forever() here because we have no other jobs
server.serve_forever()

Однако это работает только на одном ядре. Как бы вы изменили это, чтобы использовать преимущества нескольких процессов? Не ищите ответ, связанный с пушкой, ищите что-то попроще.

СОВЕТ

Вот пример кода с использованием gevent и многопроцессорной обработки, но я до сих пор не могу понять, как заставить это работать с WSGI (взято из https://gist.github.com/1169975):

import sys
from gevent import server
from gevent.baseserver import _tcp_listener
from gevent.monkey import patch_all; patch_all()
from multiprocessing import Process, current_process, cpu_count


def note(format, *args):
    sys.stderr.write('[%s]\t%s\n' % (current_process().name, format%args))

def echo(socket, address):
    print 'New connection from %s:%s' % address
    fileobj = socket.makefile()
    fileobj.write('Welcome to the echo server! Type quit to exit.\r\n')
    fileobj.write('In %s\r\n' % current_process().name)
    fileobj.flush()
    while True:
        line = fileobj.readline()
        if not line:
            print "client disconnected"
            break
        if line.strip().lower() == 'quit':
            print "client quit"
            break
        fileobj.write(current_process().name + '\t' + line)
        fileobj.flush()
        print "echoed", repr(line)

listener = _tcp_listener(('127.0.0.1', 8001))

def serve_forever(listener):
    note('starting server')
    server.StreamServer(listener, echo).serve_forever()

number_of_processes = 5
print 'Starting %s processes' % number_of_processes
for i in range(number_of_processes):
    Process(target=serve_forever, args=(listener,)).start()

serve_forever(listener)

person pokstad    schedule 13.09.2011    source источник


Ответы (2)


Так почему бы не сделать это таким же образом? https://gist.github.com/1217855

import sys
from gevent import server
from gevent.baseserver import _tcp_listener
from gevent import pywsgi
from gevent.monkey import patch_all; patch_all()
from multiprocessing import Process, current_process, cpu_count

def hello_world(env, start_response):
    if env['PATH_INFO'] == '/':
        start_response('200 OK', [('Content-Type', 'text/html')])
        return ["<b>hello world</b>"]
    else:
        start_response('404 Not Found', [('Content-Type', 'text/html')])
        return ['<h1>Not Found</h1>']

listener = _tcp_listener(('127.0.0.1', 8001))

def serve_forever(listener):
    pywsgi.WSGIServer(listener, hello_world).serve_forever()

number_of_processes = 5
print 'Starting %s processes' % number_of_processes
for i in range(number_of_processes):
    Process(target=serve_forever, args=(listener,)).start()

serve_forever(listener)
person Andrey Nikishaev    schedule 14.09.2011
comment
Но вы должны понимать, что 6 портов лучше, чем 1 и быстрее. Таким образом, 6 процессов с балансировкой nginx на 6 портах будут работать лучше, чем это. - person Andrey Nikishaev; 15.09.2011
comment
Если вы сделаете это, вы все равно создадите узкое место для одного порта в nginix. - person pokstad; 15.09.2011
comment
Это правда, но в любом случае вы будете использовать обратный прокси-сервер для своего сервера Python (из соображений безопасности), так почему бы не использовать также восходящий поток? Лучше использовать один ко многим, а затем один-один-многие. - person Andrey Nikishaev; 15.09.2011
comment
К каким проблемам безопасности уязвим этот сервер? Кажется, он лучше защищает от DoS-атак и других атак с перегрузкой памяти. Не устранит ли использование прокси-сервера преимущество использования гринлетов? - person pokstad; 15.09.2011
comment
Без обратного прокси ваше приложение может сделать что-то неожиданное, или просто убить БД, или что-то в этом роде. А вот с реверсом прокси под атакой будет только прокси. Также с обратным прокси-сервером вы можете использовать HTTPS, и это намного лучше, чем использовать их на стороне приложения. - person Andrey Nikishaev; 15.09.2011
comment
Отсутствие обратного прокси-сервера не повредит вашей производительности (конечно, если вы используете nginx или HAProxy) - person Andrey Nikishaev; 15.09.2011

Существует также утилита, которая работает с gevent для решения этой проблемы, которая называется GIPC.

https://gehrcke.de/gipc/

Преимущество в том, что вы можете передавать объекты туда и обратно из процессов и общаться. Просто мысль.

person eatmeimadanish    schedule 27.02.2018