Nate 3 лет назад
Родитель
Сommit
858d5847ee

+ 0 - 41
frameworks/Python/spyne/README.md

@@ -1,41 +0,0 @@
-# [Spyne](http://spyne.io/) Benchmark Test
-
-This is the Python Spyne portion of a [benchmarking tests suite](../../)
-comparing a variety of frameworks.
-
-The latest version is at https://github.com/arskom/spyne/tree/master/examples/tfb
-
-All test implementations are located within ([app.py](app.py))
-
-## Description
-
-Spyne + SQLAlchemy
-
-### Database
-
-PostgreSQL (psycopg2 on CPython)
-
-### Server
-
-* gunicorn+wsgi on CPython
-
-## Test URLs
-### JSON Encoding
-
-http://localhost:8080/json
-
-### Single Row Random Query
-
-With ORM:
-    http://localhost:8080/dbs
-
-Without ORM (raw):
-    http://localhost:8080/dbsraw
-
-### Variable Row Query Test
-
-With ORM:
-    http://localhost:8080/db?queries=2
-
-Without ORM (raw):
-    http://localhost:8080/dbraw?queries=2

+ 0 - 303
frameworks/Python/spyne/app.py

@@ -1,303 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-
-import spyne.const
-spyne.const.MIN_GC_INTERVAL = float('inf')
-
-from lxml import html
-
-from random import randint, shuffle, choice
-from contextlib import closing
-from email.utils import formatdate
-
-from neurons import TableModel, Application
-from neurons.daemon import ServiceDefinition, HttpServer, StaticFileServer
-from neurons.daemon.main import Bootstrapper
-
-from spyne import Integer32, Unicode, rpc, ServiceBase, Integer, Array, Any
-from spyne.protocol.html import HtmlCloth
-from spyne.protocol.http import HttpRpc
-from spyne.protocol.json import JsonDocument
-from spyne.server.wsgi import WsgiApplication
-
-if sys.version_info[0] == 3:
-    xrange = range
-
-_is_pypy = hasattr(sys, 'pypy_version_info')
-
-DBDRIVER = 'postgresql+psycopg2cffi' if _is_pypy else 'postgresql+psycopg2'
-DBHOST = 'tfb-database'
-
-
-# models
-class DbSessionManager(object):
-    def __init__(self, config):
-        self.session = config.get_main_store().Session()
-
-    def close(self, with_err):
-        self.session.close()
-
-
-class DbConnectionManager(object):
-    def __init__(self, config):
-        self.conn = config.get_main_store().engine.connect()
-
-    def close(self, with_err):
-        self.conn.close()
-
-
-class World(TableModel):
-    __tablename__ = "world"
-    _type_info = [
-        ('id', Integer32(primary_key=True)),
-        ('randomNumber', Integer32(sqla_column_args=dict(name='randomnumber'))),
-    ]
-
-
-T_INDEX = html.fromstring(open('cloths/index.html', 'rb').read())
-
-
-class Fortune(TableModel):
-    __tablename__ = "fortune"
-
-    id = Integer32(primary_key=True)
-    message = Unicode
-
-
-outprot_plain = HttpRpc(mime_type='text/plain')
-
-
-class TfbSimpleService(ServiceBase):
-    @rpc(_returns=Any)
-    def json(ctx):
-        ctx.transport.add_header('Date', formatdate(usegmt=True))
-        return dict(message=u'Hello, World!')
-
-    @rpc(_returns=Any)
-    def plaintext(ctx):
-        """Test 6: Plaintext"""
-        ctx.out_protocol = outprot_plain
-        return b'Hello, World!'
-
-
-def _force_int(v):
-    try:
-        return min(500, max(int(v), 1))
-    except:
-        return 1
-
-
-NumQueriesType = Any(sanitizer=_force_int)
-
-
-class TfbOrmService(ServiceBase):
-    @rpc(_returns=World)
-    def db(ctx):
-        retval = ctx.udc.session.query(World).get(randint(1, 10000))
-        return retval
-
-    @rpc(NumQueriesType, _returns=Array(World))
-    def dbs(ctx, queries):
-        if queries is None:
-            queries = 1
-
-        q = ctx.udc.session.query(World)
-        return [q.get(randint(1, 10000)) for _ in xrange(queries)]
-
-    @rpc(_returns=Array(Fortune, html_cloth=T_INDEX), _body_style='out_bare')
-    def fortunes(ctx):
-        # This is normally specified at the application level as it's a good
-        # practice to group rpc endpoints with similar return types under the
-        # same url fragment. eg. https://example.com/api/json
-        ctx.out_protocol = HtmlCloth()
-        ctx.outprot_ctx = ctx.out_protocol.get_context(ctx, ctx.transport)
-
-        fortunes = ctx.udc.session.query(Fortune).all()
-        fortunes.append(
-            Fortune(id=0, message=u"Additional fortune added at request time.")
-        )
-
-        fortunes.sort(key=lambda x: x.message)
-
-        return fortunes
-
-    @rpc(NumQueriesType, _returns=Array(World))
-    def updates(ctx, queries):
-        """Test 5: Database Updates"""
-
-        if queries is None:
-            queries = 1
-
-        retval = []
-        q = ctx.udc.session.query(World)
-        for id in (randint(1, 10000) for _ in xrange(queries)):
-            world = q.get(id)
-            world.randomNumber = randint(1, 10000)
-            retval.append(world)
-
-        ctx.udc.session.commit()
-
-        return retval
-
-
-class TfbRawService(ServiceBase):
-    @rpc(_returns=World)
-    def dbraw(ctx):
-        conn = ctx.udc.conn
-
-        wid = randint(1, 10000)
-        return conn.execute(
-                     "SELECT id, randomNumber FROM world WHERE id = %s", wid) \
-                                                                     .fetchone()
-
-    # returning both Any+dict or ObjectMarker+ListOfLists works
-    @rpc(NumQueriesType, _returns=Any)
-    def dbsraw(ctx, queries):
-        if queries is None:
-            queries = 1
-
-        retval = []
-        conn = ctx.udc.conn
-        for i in xrange(queries):
-            wid = randint(1, 10000)
-            result = conn.execute(
-                     "SELECT id, randomNumber FROM world WHERE id = %s", wid) \
-                .fetchone()
-            retval.append(dict(id=result[0], randomNumber=result[1]))
-
-        return retval
-
-    @rpc(_returns=Array(Fortune, html_cloth=T_INDEX), _body_style='out_bare')
-    def fortunesraw(ctx):
-        # This is normally specified at the application level as it's a good
-        # practice to group rpc endpoints with similar return types under the
-        # same url fragment. eg. https://example.com/api/json
-        ctx.out_protocol = HtmlCloth()
-        ctx.outprot_ctx = ctx.out_protocol.get_context(ctx, ctx.transport)
-
-        res = ctx.udc.conn.execute("SELECT id, message FROM fortune")
-        fortunes = res.fetchall()
-
-        fortunes.append(Fortune(
-            id=0,
-            message=u"Additional fortune added at request time."
-        ))
-
-        fortunes.sort(key=lambda x: x.message)
-
-        return fortunes
-
-    @rpc(NumQueriesType, _returns=Any)
-    def updatesraw(ctx, queries):
-        """Test 5: Database Updates"""
-        if queries is None:
-            queries = 1
-
-        conn = ctx.udc.conn
-
-        ids = [randint(1, 10000) for _ in xrange(queries)]
-
-        retval = []
-        for i in ids:
-            wid, rn = conn.execute(
-                         "SELECT id, randomNumber FROM world WHERE id=%s", i) \
-                .fetchone()
-
-            rn = randint(1, 10000)
-            retval.append(dict(id=wid, randomNumber=rn))
-
-            conn.execute("UPDATE World SET randomNumber=%s WHERE id=%s",
-                                                                        rn, wid)
-
-        return retval
-
-
-def _on_method_call_db_sess(ctx):
-    ctx.transport.add_header('Date', formatdate(usegmt=True))
-    ctx.udc = DbSessionManager(ctx.app.config)
-
-
-def _on_method_call_db_conn(ctx):
-    ctx.transport.add_header('Date', formatdate(usegmt=True))
-    ctx.udc = DbConnectionManager(ctx.app.config)
-
-
-TfbRawService.event_manager.add_listener("method_call", _on_method_call_db_conn)
-TfbOrmService.event_manager.add_listener("method_call", _on_method_call_db_sess)
-
-
-def init_app(config):
-    subconfig = config.services['root']
-
-    app = Application(
-        [TfbOrmService, TfbRawService, TfbSimpleService],
-        tns='http://techempower.com/benchmarks/Python/Spyne',
-        in_protocol=HttpRpc(),
-        out_protocol=JsonDocument(),
-        config=config,
-    )
-    if subconfig.subapps is None:
-        subconfig.subapps = {}
-
-    subconfig.subapps.update({'': app})
-
-    return subconfig.gen_site()
-
-
-def init(config):
-    return {
-        'root': ServiceDefinition(
-            init=init_app,
-            default=HttpServer(
-                type='tcp4',
-                host='127.0.0.1',
-                port=8080,
-            ),
-        ),
-    }
-
-
-def parse_config(argv):
-    from neurons.daemon.main import boot
-
-    retcode, config = boot('tfb', argv, init, bootstrapper=TfbBootstrap)
-
-    if retcode is not None:
-        sys.exit(retcode)
-
-    return config
-
-
-def gen_wsgi_app():
-    config = parse_config([])
-    app = config.services['root'].subapps[''].app
-    return WsgiApplication(app)
-
-
-words = 'some random words for you and me somebody else if then the'.split()
-
-
-class TfbBootstrap(Bootstrapper):
-    # noinspection PyUnresolvedReferences
-    def after_tables(self, config):
-        print("Generating data...")
-        with closing(config.get_main_store().Session()) as session:
-            ints = list(range(10000))
-            shuffle(ints)
-            for _ in range(10000):
-                session.add(World(randomNumber=ints.pop()))
-
-            for _ in range(100):
-                session.add(Fortune(
-                    message=' '.join([choice(words)
-                                                for _ in range(randint(3, 10))])
-                ))
-
-            session.commit()
-
-
-if __name__ == '__main__':
-    parse_config(sys.argv)
-else:
-    application = gen_wsgi_app()

+ 0 - 72
frameworks/Python/spyne/benchmark_config.json

@@ -1,72 +0,0 @@
-{
-  "framework": "spyne",
-  "tests": [{
-    "default": {
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/dbs?queries=",
-      "fortune_url": "/fortunes",
-      "update_url": "/updates?queries=",
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Micro",
-      "database": "postgres",
-      "framework": "spyne",
-      "language": "Python",
-      "flavor": "Python3",
-      "orm": "Full",
-      "platform": "Spyne",
-      "webserver": "None",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "Spyne",
-      "notes": "",
-      "versus": "wsgi"
-    },
-    "raw": {
-      "db_url": "/dbraw",
-      "query_url": "/dbsraw?queries=",
-      "fortune_url": "/fortunesraw",
-      "update_url": "/updatesraw?queries=",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Micro",
-      "database": "postgres",
-      "framework": "spyne",
-      "language": "Python",
-      "flavor": "Python3",
-      "orm": "Raw",
-      "platform": "Spyne",
-      "webserver": "None",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "Spyne-raw",
-      "notes": "",
-      "versus": "wsgi"
-    },
-    "nginx-uwsgi": {
-      "json_url": "/json",
-      "db_url": "/db",
-      "query_url": "/dbs?queries=",
-      "fortune_url": "/fortunes",
-      "update_url": "/updates?queries=",
-      "plaintext_url": "/plaintext",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Micro",
-      "database": "postgres",
-      "framework": "spyne",
-      "language": "Python",
-      "flavor": "Python3",
-      "orm": "Full",
-      "platform": "None",
-      "webserver": "nginx",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "Spyne",
-      "notes": "",
-      "versus": "wsgi"
-    }
-  }]
-}

+ 0 - 18
frameworks/Python/spyne/cloths/index.html

@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Fortunes</title>
-</head>
-<body>
-<table>
-<tr>
-  <th>id</th>
-  <th>message</th>
-</tr>
-<tr spyne-id="Fortune">
-  <td spyne-id="id"></td>
-  <td spyne-id="message"></td>
-</tr>
-</table>
-</body>
-</html>

+ 0 - 51
frameworks/Python/spyne/config.toml

@@ -1,51 +0,0 @@
-[framework]
-name = "spyne"
-
-[main]
-urls.plaintext = "/plaintext"
-urls.json = "/json"
-urls.db = "/db"
-urls.query = "/dbs?queries="
-urls.update = "/updates?queries="
-urls.fortune = "/fortunes"
-approach = "Realistic"
-classification = "Micro"
-database = "postgres"
-database_os = "Linux"
-os = "Linux"
-orm = "Full"
-platform = "Spyne"
-webserver = "None"
-versus = "wsgi"
-
-[raw]
-urls.db = "/dbraw"
-urls.query = "/dbsraw?queries="
-urls.update = "/updatesraw?queries="
-urls.fortune = "/fortunesraw"
-approach = "Realistic"
-classification = "Micro"
-database = "postgres"
-database_os = "Linux"
-os = "Linux"
-orm = "Raw"
-platform = "Spyne"
-webserver = "None"
-versus = "wsgi"
-
-[nginx-uwsgi]
-urls.plaintext = "/plaintext"
-urls.json = "/json"
-urls.db = "/db"
-urls.query = "/dbs?queries="
-urls.update = "/updates?queries="
-urls.fortune = "/fortunes"
-approach = "Realistic"
-classification = "Micro"
-database = "postgres"
-database_os = "Linux"
-os = "Linux"
-orm = "Full"
-platform = "None"
-webserver = "nginx"
-versus = "wsgi"

+ 0 - 107
frameworks/Python/spyne/gen_benchmark_config.py

@@ -1,107 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
-
-import json
-
-from spyne import AnyUri, Unicode, ComplexModel, M, UnsignedInteger16, Array
-from spyne.protocol.json import JsonDocument
-from spyne.util.dictdoc import get_object_as_dict
-
-
-class BenchmarkConfigElement(ComplexModel):
-    # exclude this from the output document
-    key = Unicode(pa={JsonDocument: dict(exc=True)})
-
-    display_name = M(Unicode)
-    notes = Unicode
-    versus = Unicode
-
-    db_url = AnyUri
-    json_url = AnyUri
-    query_url = AnyUri
-    fortune_url = AnyUri
-    update_url = AnyUri
-    plaintext_url = AnyUri
-
-    port = M(UnsignedInteger16(default=8080))
-
-    approach = M(Unicode(values=['Realistic', 'Stripped'], default='Realistic'))
-    classification = M(Unicode(values=['Micro', 'Fullstack', 'Platform'], default='Micro'))
-    database = M(Unicode(values=['none', 'mongodb', 'postgres', 'mysql'], default='none'))
-    orm = M(Unicode(values=['Full', 'Micro', 'None', 'Raw']))
-
-    framework = M(Unicode)
-    language = M(Unicode)
-    flavor = M(Unicode)
-    platform = M(Unicode)
-    webserver = M(Unicode)
-
-    os = M(Unicode(default='Linux'))
-    database_os = M(Unicode(default='Linux'))
-    
-    
-class BenchmarkConfig(ComplexModel):
-    framework = M(Unicode)
-    tests = Array(BenchmarkConfigElement, wrapped=False)
-
-
-gen_raw_test = lambda: BenchmarkConfigElement(
-    display_name="Spyne RAW",
-    db_url="/dbsraw",
-    query_url="/dbraw?queries=",
-    fortune_url="/fortunesraw",
-    update_url="/raw-updates?queries=",
-    orm='Raw',
-)
-
-gen_normal_test = lambda: BenchmarkConfigElement(
-    display_name="Spyne ORM",
-    db_url="/dbs",
-    query_url="/db?queries=",
-    fortune_url="/fortunes",
-    update_url="/updatesraw?queries=",
-    orm='Full',
-)
-
-
-def add_common(bc):
-    bc.port = 8080
-    bc.approach = "Realistic"
-    bc.classification = "Micro"
-    bc.database = "postgres"
-    bc.framework = "spyne"
-    bc.language = "Python"
-    bc.platform = "Spyne"
-    bc.webserver = "None"
-    bc.os = "Linux"
-    bc.database_os = "Linux"
-    bc.versus = "wsgi"
-    bc.plaintext_url = "/plaintext"
-    return bc
-
-
-config = BenchmarkConfig(framework='spyne', tests=[])
-
-keys = iter(['default', 'raw', 'py3orm', 'py3raw'])
-
-for flav in ['CPython', 'Python3']:
-    bc = add_common(gen_normal_test())
-    bc.flavor = flav
-    bc.key = next(keys)
-    config.tests.append(bc)
-
-    bc = add_common(gen_raw_test())
-    bc.flavor = flav
-    bc.key = next(keys)
-    config.tests.append(bc)
-
-data = get_object_as_dict(config, complex_as=dict)
-data['tests'] = [{d['key']: d} for d in data['tests']]
-
-data = json.dumps(data, indent=2, sort_keys=True, separators=(',', ': '))
-
-open('benchmark_config.json', 'wb').write(data)
-
-
-print(data)

+ 0 - 10
frameworks/Python/spyne/gunicorn_conf.py

@@ -1,10 +0,0 @@
-import multiprocessing
-import os
-import sys
-
-workers = multiprocessing.cpu_count() * 3
-
-bind = "0.0.0.0:8080"
-keepalive = 120
-errorlog = '-'
-pidfile = 'gunicorn.pid'

+ 0 - 48
frameworks/Python/spyne/nginx.conf

@@ -1,48 +0,0 @@
-# This file is based on /usr/local/nginx/conf/nginx.conf.default.
-
-# One worker process per core
-error_log stderr error;
-
-events {
-    # This needed to be increased because the nginx error log said so.
-    # http://nginx.org/en/docs/ngx_core_module.html#worker_connections
-    worker_connections  65535;
-    multi_accept on;
-}
-
-http {
-    default_type  application/octet-stream;
-    client_body_temp_path      /tmp;
-
-    # turn off request logging for performance
-    access_log off;
-
-    # I think these only options affect static file serving
-    sendfile        on;
-    tcp_nopush      on;
-
-    # Allow many HTTP Keep-Alive requests in a single TCP connection before
-    # closing it (the default is 100). This will minimize the total number
-    # of TCP connections opened/closed. The problem is that this may cause
-    # some worker processes to be handling too connections relative to the
-    # other workers based on an initial imbalance, so this is disabled for
-    # now.
-#    keepalive_requests 1000;
-
-    #keepalive_timeout  0;
-    keepalive_timeout  65;
-
-    server {
-        # For information on deferred, see:
-        # http://nginx.org/en/docs/http/ngx_http_core_module.html#listen
-        # http://www.techrepublic.com/article/take-advantage-of-tcp-ip-options-to-optimize-data-transmission/
-        # The backlog argument to listen() is set to match net.ipv4.tcp_max_syn_backlog and net.core.somaxconn
-        listen       8080 default_server deferred reuseport backlog=65535;
-        server_name  localhost;
-
-        location / {
-            uwsgi_pass unix:/var/tmp/uwsgi.sock;
-            include /usr/local/nginx/conf/uwsgi_params;
-        }
-    }
-}

+ 0 - 28
frameworks/Python/spyne/requirements.txt

@@ -1,28 +0,0 @@
-attrs==18.2.0
-Automat==0.7.0
-colorama==0.4.1
-constantly==15.1.0
-greenlet==0.4.15
-gunicorn==19.9.0
-hyperlink==18.0.0
-idna==2.8
-incremental==17.5.0
-lxml==4.6.5
-meinheld==0.6.1
-msgpack-python==0.5.6
-neurons==0.8.4
-ply==3.11
-psycopg2==2.7.7
-pycrypto==2.6.1
-PyHamcrest==1.9.0
-pytz==2018.9
-PyYAML==5.4
-six==1.12.0
-slimit==0.8.1
-spyne==2.13.9a0
-SQLAlchemy==1.2.17
-Twisted==22.2.0
-txpostgres==1.6.0
-Werkzeug==0.15.3
-zope.interface==4.6.0
-uwsgi==2.0.18

+ 0 - 19
frameworks/Python/spyne/spyne-nginx-uwsgi.dockerfile

@@ -1,19 +0,0 @@
-FROM python:3.6.6-stretch
-
-RUN curl -s http://nginx.org/keys/nginx_signing.key | apt-key add -
-RUN echo "deb http://nginx.org/packages/debian/ stretch nginx" >> /etc/apt/sources.list
-RUN echo "deb-src http://nginx.org/packages/debian/ stretch nginx" >> /etc/apt/sources.list
-
-RUN apt-get update -yqq && apt-get install -yqq nginx
-
-ADD ./ /spyne
-
-WORKDIR /spyne
-
-RUN pip3 install -r /spyne/requirements.txt
-
-RUN sed -i 's|include .*/conf/uwsgi_params;|include /etc/nginx/uwsgi_params;|g' /spyne/nginx.conf
-
-EXPOSE 8080
-
-CMD nginx -c /spyne/nginx.conf && uwsgi --ini /spyne/uwsgi.ini --processes $(($(nproc)*3)) --wsgi app:application

+ 0 - 11
frameworks/Python/spyne/spyne-raw.dockerfile

@@ -1,11 +0,0 @@
-FROM python:3.6.6-stretch
-
-ADD ./ /spyne
-
-WORKDIR /spyne
-
-RUN pip3 install -r /spyne/requirements.txt
-
-EXPOSE 8080
-
-CMD gunicorn app:application -c gunicorn_conf.py

+ 0 - 11
frameworks/Python/spyne/spyne.dockerfile

@@ -1,11 +0,0 @@
-FROM python:3.6.6-stretch
-
-ADD ./ /spyne
-
-WORKDIR /spyne
-
-RUN pip3 install -r /spyne/requirements.txt
-
-EXPOSE 8080
-
-CMD gunicorn app:application -c gunicorn_conf.py

+ 0 - 53
frameworks/Python/spyne/tfb.yaml

@@ -1,53 +0,0 @@
-ServiceDaemon:
-    alert_dests: []
-    autoreload: false
-    daemonize: false
-    debug: true
-    debug_reactor: false
-    file_version: 2
-    log_cloth: false
-    log_dbconn: false
-    log_interface: false
-    log_model: false
-    log_orm: false
-    log_protocol: false
-    log_queries: false
-    log_results: false
-    log_rss: false
-    log_sqlalchemy: false
-    logger_dest_rotation_compression: gzip
-    logger_dest_rotation_period: WEEKLY
-    loggers:
-    -   Logger:
-            level: ERROR
-            path: .
-    main_store: sql_main
-    name: tfb
-    services:
-    -   HttpServer:
-            backlog: 50
-            disabled: true
-            host: 127.0.0.1
-            name: root
-            port: 8080
-            subapps:
-            -   HttpApplication:
-                    url: ''
-            type: tcp4
-    stores:
-    -   RelationalStore:
-            async_pool: true
-            backend: sqlalchemy
-            conn_str: postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world
-            echo_pool: false
-            max_overflow: 3
-            name: sql_main
-            pool_pre_ping: true
-            pool_recycle: 3600
-            pool_size: 10
-            pool_timeout: 30
-            pool_use_lifo: false
-            sync_case_sensitive: false
-            sync_pool: true
-            sync_pool_type: QueuePool
-    uuid: fef52ff8-3103-11e9-b0e1-5453edabe249

+ 0 - 19
frameworks/Python/spyne/uwsgi.ini

@@ -1,19 +0,0 @@
-[uwsgi]
-master
-; Increase listen queue used for nginx connecting to uWSGI. This matches
-; net.ipv4.tcp_max_syn_backlog and net.core.somaxconn.
-listen = 16384
-; for performance
-disable-logging
-; use UNIX sockets instead of TCP loopback for performance
-socket = /var/tmp/uwsgi.sock
-; allow nginx to access the UNIX socket
-chmod-socket = 666
-; Avoid thundering herd problem http://uwsgi-docs.readthedocs.org/en/latest/articles/SerializingAccept.html .
-; This is currently disabled because when I tried it with flask, it caused a
-; 20% performance hit. The CPU cores could not be saturated with thunder-lock.
-; I'm not yet sure the full story, so this is presently disabled. Also,
-; disabling this caused bottle to get ~13% faster.
-;thunder-lock
-; used by uwsgi_stop.ini
-pidfile = /var/tmp/uwsgi.pid