PyPy插件
要求uWSGI >= 2.0.9
介绍
想法/设计:Maciej Fijalkowski
贡献者:Alex Gaynor, Armin Rigo
自uWSGI 1.9.11起,就有了一个基于cffi的PyPy插件。老且慢的基于cpyext的已经从版本树中移除了。
目前,只在Linux系统上支持该插件。接下来的发布版本也会支持其他平台。
这个插件在启动的时候加载 libpypy-c.so
,设置PyPy安装目录,并且执行一个实现插件逻辑的特别的Python模块。所以是哒,大多数的插件都是用Python实现的,并且理论上讲,这个方法将允许除了C, C++和Objective-C之外,直接用Python编写uWSGI插件。
截至2014年12月,已经合并了到PyPy的所有所需插件,因此你可以获取一个官方最新版本 (或者一个于2014年12月后发布的稳定版本),然后与uWSGI一起使用它。
安装带PyPy支持的uWSGI
与往常一样,使用uWSGI,你有不同的方法基于你的需求安装uWSGI。
如果你已在PyPy家目录安装了pip,那么可以运行
- pip install uwsgi
这个uwsgi setup.py文件将会识别PyPy环境,并且构建一个仅PyPy的uWSGI二进制文件。
使用相同的方式,你可以执行uWSGI源码中提供的setup.py:
- pypy setup.py install
(这两种方法将会把pypy家目录硬编码到uWSGI二进制文件中,因此,你无需在你的选项中设置pypy-home)
或者你可以手工编译:
- UWSGI_PROFILE=pypy make
或者可以使用网络安装程序:
- curl https://uwsgi.it/install | bash -s pypy /tmp/uwsgi
这将会在 /tmp/uwsgi
中构建一个uWSGI + PyPy二进制文件
或者你可以把PyPy支持当成插件构建。
- uwsgi --build-plugin plugins/pypy
或者(旧式)
- python uwsgiconfig.py --plugin plugins/pypy
PyPy家目录
uWSGI Python插件 (更准确的说,是CPython插件) 通过链接 libpython
工作。这意味着,对于Python的每一个不同的版本,你都需要重新构建这个插件。而这个PyPy插件不同,因为libpypy-c是在启动时加载的,而它的符号在运行时解决。这允许你动态迁移到一个不同的PyPy版本。
这个方法的“缺点”是,你需要在运行时通知uWSGI你的PyPy安装在哪里 (除非你是通过pip或者使用setup.py脚本来安装uwsgi的,在这样的情况下,会自动找到家目录)
假设你的PyPy位于 /opt/pypy
,你可以这样启动uWSGI:
- uwsgi --http-socket :9090 --pypy-home /opt/pypy
通过这个命令行,uWSGI将会搜索 /opt/pypy/bin/libpypy-c.so
,如果找到,它将会设置那个路径为PyPy家目录。
如果你的 libpypy-c.so
位于PyPy家目录之外 (并且位于一个动态链接器不可达的目录中),那么你可以使用 —pypy-lib
选项。
- uwsgi --http-socket :9090 --pypy-home /opt/pypy --pypy-lib /opt/libs/libpypy-c.so
通过这个方法,你可以使用来自一个指定PyPy构建的库,以及来自其他的家目录。
注解
如果你想指向当前目录下的一个.so文件,那么记得给–pypy-lib加上前缀./!
PyPy设置文件
如前所述,大多数的uWSGI PyPy插件都是用Python写的。该代码于运行时加载,你也可以自定义它。
是哒,这就意味着你无需重新构建uWSGI就可以改变这个插件的工作方式。
pypy_setup.py
文件的默认版本被嵌入到uWSGI二进制文件中,而它自动在启动时加载。
如果你想改变它,那么仅需通过 —pypy-setup
选项传递另一个文件名。
- uwsgi --http-socket :9090 --pypy-home /opt/pypy --pypy-lib /opt/libs/libpypy-c.so --pypy-setup /home/foobar/foo.py
这个Python模块实现了uWSGI钩子和用于访问来自你的应用的uWSGI API的虚拟 uwsgi
python模块。
如果你想要检索嵌入的pypy_setup.py文件的内容,那么你可以通过使用 print-sym
这个便捷选项来从二进制符号中读取它。
- uwsgi --print-sym uwsgi_pypy_setup
WSGI支持
该插件实现了PEP 333和PEP 3333。你可以同时加载WSGI模块和 mod_wsgi
样式的 .wsgi
文件。
要加载一个WSGI模块 (它必须位于你的Python路径中):
- uwsgi --http-socket :9090 --pypy-home /opt/pypy --pypy-wsgi myapp
要加载一个WSGI文件:
- uwsgi --http-socket :9090 --pypy-home /opt/pypy --pypy-wsgi-file /var/www/myapp/myapp.wsgi
RPC支持
你可以使用 uwsgi.register_rpc()
API函数来注册RPC函数,就像你可以使用普通的Python插件一样。
- import uwsgi
- def hello():
- return "Hello World"
- uwsgi.register_rpc('hello', hello)
要调用RPC函数, uwsgi.rpc()
和 uwsgi.call()
都可以用。
- import uwsgi
- uwsgi.rpc('192.168.173.100:3031', 'myfunc', 'myarg')
- uwsgi.call('myfunc', 'myarg')
- uwsgi.call('myfunc@192.168.173.100:3031', 'myarg')
(与本地RPC) 集成已经在PyPy和PyPy, PyPy和JVM, 以及PyPy和Lua之前测试过了。所有这些都工作得十分完美……因此,那意味着你可以调用来自PyPy的Java函数。
IPython技巧
用一个用于测试的运行中的shell是非常非常棒的。你可以使用IPython来实现。
- uwsgi --socket :3031 --pypy-home /opt/pypy --pypy-eval "import IPython; IPython.embed()" --honour-stdin
uWSGI API状态
自20130526起,支持以下API函数、钩子和属性。
uwsgi.opt
uwsgi.post_fork_hook
uwsgi.add_cron()
uwsgi.setprocname()
uwsgi.alarm()
uwsgi.signal_registered()
uwsgi.mule_id()
uwsgi.worker_id()
uwsgi.masterpid()
uwsgi.lock()
uwsgi.unlock()
uwsgi.add_file_monitor()
uwsgi.add_timer()
uwsgi.add_rb_timer()
uwsgi.cache_get()
uwsgi.cache_set()
uwsgi.cache_update()
uwsgi.cache_del()
uwsgi.signal()
uwsgi.call()
uwsgi.rpc()
uwsgi.register_rpc()
uwsgi.register_signal()
选项
pypy-lib
- 加载指定的libpypy-s.sopypy-setup
- 加载指定的pypy_setup脚本文件pypy-home
- 设置pypy家目录pypy-wsgi
- 加载一个WSGI模块pypy-wsgi-file
- 加载一个mod_wsgi兼容的.wsgi文件pypy-eval
- 在fork()
之前执行指定的字符串pypy-eval-post-fork
- 在每个fork()
之后执行指定的字符串pypy-exec
- 在fork()
之前执行指定的python脚本pypy-exec-post-fork
- 在每个fork()
之后执行指定的python脚本pypy-pp/pypy-python-path/pypy-pythonpath
- 添加指定项到pythonpathpypy-paste
- 加载一个paste.deploy .ini配置pypy-ini-paste
- 加载一个paste.deploy .ini配置,并使用它的[uwsgi]部分
注意事项
- 混合libpython和libpypy-c是明确禁止的。pypy插件中的检查阻止你做这种地狱般的事情。
- 从一个Python程序员的观点来看,PyPy插件一般较为“正统”,而CPython在许多领域也许有点亵渎。我们已经能够进行抉择了,因为我们无需向后兼容较老的uWSGI发行版。
- uWSGI API仍然未完成
- WSGI加载器并不更新uWSGI内部应用列表,因此,诸如
—need-app
这样的东东并不能用。即使应用已成功被加载,服务器也会在启动时报告”dynamic mode”。这将会很快被修复。