摘要:uwsgi执行顺序:启动master进程,执行python脚本的公共代码(import同一层)。然后生成worker进程,uwsgi.post_fork_hook=init_functions,初始化生成work子进程。然后请求来临时,每个子进程执行application代码

配置文件ini:

[uwsgi]

socket=192.168.62.20:8001

http=192.168.62.20:8003

master=true

pythonpath=../

module=breapi

processes=12

listen=256

disable-logging=true

daemonize=uwsgi.log

pidfile=uwsgi.pid

vacuum=true

harakiri=5

buffer-size=36384

stats=127.0.0.1:1717

原文http://pythonpaste.org/do-it-yourself-framework.html,http://blog.xsudo.com/archives/530.html

一个用来diy的框架

什么是WSGI

wsgi是一个在web服务器和应用程序app之间统一的接口,这样来规范app和web server,说的简单一点就是规范的接受web请求(request),但是不仅如此

1 你在类似CGI环境里分发传递,意味着数据可以在登录用户安全传递

2 在类似CGI环境里传递更多的上下文信息,脚本名称和路径

3 你可以扩展自身的wsgi环境,并允许回调,扩展信息并插入python对象,任何你想添加的却不能在http头里添加的

wsgi不仅仅是在web和应用之间,可以用在交互的每个层面 ,这使得应用app变成lib库,可以很好的扩展和重用

写一个wsgi应用

我们来简单的写一个wsgi的应用

简短的一个摘要

1 一个简单的wsgi应用就是一个可调用的对象比如一个function,有两个参数environ 和 start_response

2 环境environment是一个字典,python的标准字典有一些传统的http参数比如REQUEST_METHOD和HTTP_POST

3 environment可以包含一些特别的键wsgi.input 像post请求里的输入流

4 start_response是一个返回客户端结果的方法,需要提供http的状态和headers

start_response 是一个接受两个必需的固定参数和一个可选参数的 callable 对象. 为便于说明, 我们把这三个参数分别命名为: status, response_headers, 和 exc_info, 当然你也可以给他们起其他名字. 应用程序必需使用固定参数调用 start_response (比如:

start_response(status,response_headers)) , 参数 status 是一个形如 “999 Message here” 的表示状态的字符串。而 response_headers 参数是一个描述 http 响应头的列表, 其中每一个元素都是像 (header_name,header_value) 这样的元组。可选的 exc_info 参数会在后面的 start_response() callable 和 错误处理 两节中进行描述,该参数只有在应用程序产生了错误并希望在浏览器上显示错误信息的时候才用得上。

5 最后应用返回一个含有迭代器的response(通常是一个字符串列表)

例子

1

2

3
def app(environ, start_response):

    start_response('200
OK', [('content-type', 'text/html')])

    return ['Hello
world!']

然后更简单的一个server来运行这个app

1

2

3
if __name__ == '__main__':

    from paste import httpserver

    httpserver.serve(app, host='127.0.0.1', port='8080')

这样就可以在本机用8080端口来请求他了

一个带有互动的例子

1

2

3

4

5

6

7

8

9

10
from paste.request import parse_formvars

def app(environ, start_response):

    fields = parse_formvars(environ)

    if environ['REQUEST_METHOD'] == 'POST':

        start_response('200
OK', [('content-type', 'text/html')])

        return ['Hello,
', fields['name'], '!']

    else:

        start_response('200
OK', [('content-type', 'text/html')])

        return ['<form
method="POST">Name: <input type="text" '

                'name="name"><input type="submit"></form>']

这些都很简单,我们需要更多的页面,测试还有运行环境

对象发布 Object publishing

一个典型的对象发布 转换 ‘/’ 为 ‘..’

/articles/view?id=5 转换为 root.articles.view(id=5)

我们必须启动相应的对象

1

2

3

4

5

6
class ObjectPublisher(object):

def __init__(self, root):

        self.root = root

def __call__(self, environ, start_response):

        ...

app = ObjectPublisher(my_root_object)

我们重写__call__方法来实现一个callable ObjectPublisher ,就像一个wsgi的方法,现在我们要做的事情就是传递environ进去,调用它,然后返回结果response

路径

WSGI会把请求的路径放到两个变量SCRIPT_NAME和PATH_INFO里

SCRIPT_NAME就是我们将要到达的地方脚本名称,PATH_INFO就是请求的路径,这是框架寻找对象的方式

我们来实现__call__方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31
def __call__(self, environ, start_response):

    fields = parse_formvars(environ)

    obj = self.find_object(self.root, environ)

    response_body = obj(**fields.mixed())

    start_response('200
OK', [('content-type', 'text/html')])

    return [response_body]

def find_object(self, obj, environ):

    path_info = environ.get('PATH_INFO', '')

    if not path_info or path_info == '/':

        # We've arrived!

        return obj

    # PATH_INFO always starts with a /, so we'll get rid of it:

    path_info = path_info.lstrip('/')

    # Then split the path into the "next" chunk, and everything

    # after it ("rest"):

    parts = path_info.split('/', 1)

    next = parts[0]

    if len(parts) == 1:

        rest = ''

    else:

        rest = '/' +
parts[1]

    # Hide private methods/attributes:

    assert not next.startswith('_')

    # Now we get the attribute; getattr(a, 'b') is equivalent

    # to a.b...

    next_obj = getattr(obj, next)

    # Now fix up SCRIPT_NAME and PATH_INFO...

    environ['SCRIPT_NAME'] += '/' +
next

    environ['PATH_INFO'] = rest

    # and now parse the remaining part of the URL...

    return self.find_object(next_obj, environ)

现在用ObjectPublisher来包装应用,并放到一个包中去

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16
from objectpub import ObjectPublisher

class Root(object):

# The "index" method:

    def __call__(self):

        return '''

        <form action="welcome">

        Name: <input type="text" name="name">

        <input type="submit">

        </form>

        '''

def welcome(self, name):

        return 'Hello
%s!' % name

app = ObjectPublisher(Root())

if __name__ == '__main__':

    from paste import httpserver

    httpserver.serve(app, host='127.0.0.1', port='8080')

需要注意的是,本来WSGI是要传入一个app的方法的,于是这里用了对象,并实现了__call__方法,结果是一样的

我们会发现缺少很多东西,比较特殊的我们没有地方去设置输出的headers,还有request里的信息是很少的

1

2

3

4

5

6

7

8

9

10

11
# This is just a dictionary-like object that has case-

# insensitive keys:

from paste.response import HeaderDict

class Request(object):

    def __init__(self, environ):

        self.environ = environ

        self.fields = parse_formvars(environ)

class Response(object):

    def __init__(self):

        self.headers = HeaderDict(

            {'content-type': 'text/html'})

我们不想改变方法,但是不能让request对象和response对象在全局的变量里,因为我们想要线程安全

修改__call__方法为

1

2

3

4

5

6

7

8

9

10

11
import threading

webinfo = threading.local()

class ObjectPublisher(object):

    ...

def __call__(self, environ, start_response):

        webinfo.request = Request(environ)

        webinfo.response = Response()

        obj = self.find_object(self.root, environ)

        response_body = obj(**dict(webinfo.request.fields))

        start_response('200
OK', webinfo.response.headers.items())

        return [response_body]

现在在我们的方法里可以这么做

1

2

3
class Root:

    def rss(self):

        webinfo.response.headers['content-type'] = 'text/xml'



一个UWSGI的例子的更多相关文章

  1. 用一个简单的例子来理解python高阶函数

    ============================ 用一个简单的例子来理解python高阶函数 ============================ 最近在用mailx发送邮件, 写法大致如 ...

  2. Spring-Context之一:一个简单的例子

    很久之前就想系统的学习和掌握Spring框架,但是拖了很久都没有行动.现在趁着在外出差杂事不多,就花时间来由浅入深的研究下Spring框架.Spring框架这几年来已经发展成为一个巨无霸产品.从最初的 ...

  3. 高仿“点触验证码”做的一个静态Html例子

    先上源码: <html> <head> <title>TouClick - Designed By MrChu</title> <meta htt ...

  4. 关于apriori算法的一个简单的例子

    apriori算法是关联规则挖掘中很基础也很经典的一个算法,我认为很多教程出现大堆的公式不是很适合一个初学者理解.因此,本文列举一个简单的例子来演示下apriori算法的整个步骤. 下面这个表格是代表 ...

  5. 扩展Python模块系列(二)----一个简单的例子

    本节使用一个简单的例子引出Python C/C++ API的详细使用方法.针对的是CPython的解释器. 目标:创建一个Python内建模块test,提供一个功能函数distance, 计算空间中两 ...

  6. fitnesse - 一个简单的例子(slim)

    fitnesse - 一个简单的例子(slim) 2017-09-30 目录1 编写测试代码(Fixture code)2 编写wiki page并运行  2.1 新建wikiPage  2.2 运行 ...

  7. Struts2的配置和一个简单的例子

    Struts2的配置和一个简单的例子 笔记仓库:https://github.com/nnngu/LearningNotes 简介 这篇文章主要讲如何在 IntelliJ IDEA 中使用 Strut ...

  8. 一个简单的例子搞懂ES6之Promise

    ES5中实现异步的常见方式不外乎以下几种: 1. 回调函数 2. 事件驱动 2. 自定义事件(根本上原理同事件驱动相同) 而ES6中的Promise的出现就使得异步变得非常简单.promise中的异步 ...

  9. 一个简单的例子了解states

    在大规模的配置管理工作中,我们要编写大量的states.sls文件.top.sls是states系统的入口文件,它负责指定哪些设备调用哪些states.sls文件.statse的默认工作目录是在/sr ...

随机推荐

  1. 其他信息: Error creating context 'spring.root': 未能加载文件或程序集“EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”或它的某一个依赖项

    详细错误情况: “System.Configuration.ConfigurationErrorsException”类型的异常在 Spring.Core.dll 中发生,但未在用户代码中进行处理 其 ...

  2. linux配置使用外部smtp发送邮件

    mail命令需要设定mail.rc(或nail.rc)文件, set from=user@domain.comset smtp=smtp.domain.comset smtp-auth-user=us ...

  3. Python 线程,进程

    Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元 线程不能实现多并发 只能实现伪并发 每次工作 只能是一个线程完成 由于python解释器 原生是c  原生线程 底层都会有一把 ...

  4. ASP:GB2312格式文本文件转换成UTF-8格式

    '-------------------------------------------------'函数名称:gb2utf_file'作用:利用AdoDb.Stream对象来把GB2312格式文本文 ...

  5. Win32串口API

    在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信方便易行,应用广泛. 一般情况下,工控机和各智能仪表通过RS485总线进行通信.RS485的通信方式是半 ...

  6. hdu5269 ZYB loves Xor I

    分治法和字典树都可以,都是递归,但字典树耗内存 从第一bit开始,若相同则xor为0,分到同一部分,不相同则统计,且此时lowbit为这一bit,最后结果要乘以2 /*分治法*/ #include&l ...

  7. WinRAR5.31 注册码

    RAR registration dataState Grid Corporation Of China50000 PC usage licenseUID=5827a0bd1c43525d0a5d64 ...

  8. POJ3468--A Simple Problem with Integers--线段树/树状数组 改段求段

    题目描述 You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type ...

  9. A*算法实现

    A* 算法非常简单.算法维护两个集合:OPEN 集和 CLOSED 集.OPEN 集包含待检测节点.初始状态,OPEN集仅包含一个元素:开始位置.CLOSED集包含已检测节点.初始状态,CLOSED集 ...

  10. Python虚拟环境安装virtualenv

    解决了多个版本共存的问题 virtualenv 为每个不同项目提供一份 Python 安装.它并没有真正安装多个 Python 副本,但是它确实提供了一种巧妙的方式来让各项目环境保持独立. 安装vir ...