我的程序是用python结合bottle框架写的,但bottle自带wsgi原本只是单进程单线程运行模式(Bottle 默认运行在内置的 wsgiref 服务器上面。这个单线程的 HTTP 服务器在开发的时候特别有用,但其性能低下,在服务器负载不断增加的时候也许会是性能瓶颈, 一次只能响应一个请求)。为了提升程序的处理能力,首先要启用多线程,即在程序中使用gevent( 大多数服务器的线程池都限制了线程池中线程的数量,避免创建和切换线程的代价。尽管和进程 (fork)比起来,线程还是挺便宜的。但是也没便宜到可以接受为每一个请求创建一个线程。gevent 模块添加了 greenlet 的支持。 greenlet 和传统的线程类似,但其创建只需消耗很少的资源。基于 gevent 的服务器可以生成成千上万的 greenlet,为每个连接分配一个 greenlet 也毫无压力。阻塞greenlet,也不会影响到服务器接受新的请求。同时处理的连接数理论上是没有限制的。)。只需要在run中加上 server='gevent',如下:

1 import gevent
2 from gevent import monkey.patch_all()
3 代码段……
4 run(host='0.0.0.0', port=8080, server='gevent')

尽管使用了多线程模式,但这些线程都是跑在一个进程里,所以需要开启多个进程来进一步提升并发处理能力,因此在启用脚本的时候,在run(port=)里,端口号不能写死,应该使用变量来传递,如下代码(在脚本执行时,在需带一个参数,这个参数是大于1024的整数,否则报错停止脚本):

import gevent,sys
from gevent import monkey.patch_all()
#获取端口号
try:
portnum = int(sys.argv[1])
except Exception,e:
print "请带上整数类型的端口号启动此程序"
logging.error("请带上整数类型的端口号启动此程序")
sys.exit(1)
if portnum <= 1024:
print "端口号请大于1024!"
logging.error("端口号请大于1024!")
sys.exit(1)
代码段……
run(host='0.0.0.0', port=portnum , server='gevent')

执行方式如下(osyw.py是我python程序名):

python osyw.py 1124

如果纯靠手动操作这些,在生产上,很不方便,所以我写了个shell来管理,这个shell定义了多个端口号,然后去循环启用或停止python进程,脚本大概如下(是用httpd改写的):

#!/bin/bash
#
# osyw Startup script for the osyw HTTP Server
#
# chkconfig: - 88 18
# description: osyw
# processname: osyw
# config:
# config: /home/bottle/osyw/
# pidfile: /var/run/osyw.pid
#
### BEGIN INIT INFO
# Provides: osyw
# Short-Description: start and stop osyw HTTP Server
# Description: The osyw HTTP Server is an extensible server
# implementing the current HTTP standards.
### END INIT INFO
# Source function library.
. /etc/rc.d/init.d/functions
# Path to the apachectl script, server binary, and short-form for messages.
port_list=(8811 8812 8813) #设置了3个端口
#pidfile='/var/run/osyw.pid'
pro_path='/var/www/osyw/osyw.py' #程序路径
log_path='/var/www/osyw/log/access.log' #访问日志路径
RETVAL=0
start() {
for i in ${port_list[*]}
do
p=`/usr/sbin/lsof -i :${i} |wc -l`
if [ ${p} -ge 2 ]
then
action "osyw ${i} already exists !" /bin/false
else
/usr/bin/python ${pro_path} ${i} &>> ${log_path}
RETVAL=$?
if [ ${RETVAL} == 0 ]
then
action "osyw ${i} start ..." /bin/true
else
action "osyw ${i} start ..." /bin/false
fi
fi
done
return $RETVAL
}
stop() {
for i in ${port_list[*]}
do
pidfile="/var/run/osyw_${i}.pid"
if [ -f ${pidfile} ]
then
pid=`cat ${pidfile}`
kill -9 ${pid}
RETVAL=$?
if [ ${RETVAL} == 0 ]
then
action "osyw ${i} stop ..." /bin/true
else
action "osyw ${i} stop ..." /bin/false
fi
rm -f ${pidfile}
else
action "osyw ${i} Has stopped !" /bin/false
fi
done
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status -p ${pidfile} 'osyw'
RETVAL=$?
;;
restart)
stop
sleep 2
start
;;
condrestart|try-restart)
if status -p ${pidfile} 'osyw' >&/dev/null; then
stop
start
fi
;;
force-reload|reload)
reload
;;
*)
echo $"Usage: $prog {start|stop|restart|condrestart|try-restart|force-reload|reload|status|fullstatus|graceful|help|configtest}"
RETVAL=2
esac
exit $RETVAL

效果图:

本人的代码是用svn管理的,所以上传代码后,SVN钩子会调用shell脚本来重启这些程序,以下是SVN钩子代码:

export LANG=en_US.UTF-8
/usr/bin/svn update --username xxxx --password xxxxxxxx /var/bottle
/bin/bash /etc/init.d/osyw restart

当然,为了结合shell,python程序里也要做一些处理,如自动把程序转为后台守护进程,然后把进程ID写入文件,以下是关键的python代码:

#定义PID路径
pid_path = '/var/run/osyw_%s.pid' % portnum def daemonize():
"""把本脚本转为守护进程"""
try:
pid=os.fork()
if pid>0:
sys.exit(0)
except Exception,e:
logging.error(e)
sys.exit(1) os.chdir('/')
os.umask(0)
os.setsid() try:
pid=os.fork()
if pid>0:
sys.exit(0)
except Exception,e:
logging.error(e)
sys.exit(1) PID = str(os.getpid())
with open(pid_path,'w') as f:
f.write(PID) 其它代码段…… if __name__ == '__main__':
try:
from oscore import setting #导入配置文件
if setting.status == 'online': #如果配置中是线上的,则程序转入后台运行
daemonize()
except Exception:
pass app = default_app()
app = SessionMiddleware(app, session_opts) #sessionMiddleware是session插件
run(app=app,host='0.0.0.0', port=portnum,server='gevent')

最好,用nginx代理来负载这些端口,我nginx和python程序是安装在同一台服务器上的:

以上是nginx反向代理的部分代码:

upstream myweb {
#ip_hash;
server 192.168.1.240:8811 weight=4 max_fails=2 fail_timeout=30s;
server 192.168.1.240:8812 weight=4 max_fails=2 fail_timeout=30s;
server 192.168.1.240:8813 weight=4 max_fails=2 fail_timeout=30s;
}
server {
listen 80;
server_name 192.168.1.240;
location /
{
proxy_pass http://myweb;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_cache_key $host$uri$is_args$args;
}
access_log off;
}

做完这些后,当访问80端口时,nginx就会平均轮洵分配到每个端口上去,实现了多进程,多线程的运行模式,更有效的提升了并发处理能力

python bottle使用多个端口(多个进程)提高并发的更多相关文章

  1. python bottle框架

    python bottle框架 简介: Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Python的标准库外,其不依赖任何其他模块. Bottl ...

  2. Python+Bottle+Sina SAE快速构建网站

    Bottle是新生一代Python框架的代表,利用Bottle构建网站将十分简单. Sina SAE是国内较出名的云平台之一,十分适用于个人网站的开发或创业公司网站开发. 下面将介绍如果通过Pytho ...

  3. python bottle框架(WEB开发、运维开发)教程

    教程目录 一:python基础(略,基础还是自己看书学吧) 二:bottle基础 python bottle web框架简介 python bottle 框架环境安装 python bottle 框架 ...

  4. 解决基于BAE python+bottle开发上的一系列问题 - artwebs - 博客频道 - CSDN.NET

    解决基于BAE python+bottle开发上的一系列问题 - artwebs - 博客频道 - CSDN.NET 解决基于BAE python+bottle开发上的一系列问题 分类: python ...

  5. 让python bottle框架支持jquery ajax的RESTful风格的PUT和DELETE等请求

    这两天在用python的bottle框架开发后台管理系统,接口约定使用RESTful风格请求,前端使用jquery ajax与接口进行交互,使用POST与GET请求时都正常,而Request Meth ...

  6. Windows - 杀死占用某个端口号的进程

    Windows不像Linux,Unix那样,ps -ef 查出端口和进程号,然后根据进程号直接kill进程. Windows根据端口号杀死进程要分三步: 第一步 根据 端口号 寻找 进程号 C:\&g ...

  7. win7命令行 端口占用 查询进程号 杀进程

    打开CMD窗口 win+R–>cmd 根据端口号查找进程号 netstat -nao|grep 端口号 根据进程号得到进程名 tasklist |findstr 进程号 杀进程 taskkill ...

  8. windows下根据端口号杀死进程

    Windows不像Linux,Unix那样,ps -ef 查出端口和进程号,然后根据进程号直接kill进程. Windows根据端口号杀死进程要分三步: 第一步 根据端口号寻找进程号 C:\>n ...

  9. Windows查看端口被哪个进程占用

    命令 查看PID: netstat -ano|findstr 端口号 查看进程名称: tasklist|findstr PID 结束进程: taskkill -F -PID PID号 配图详解: 1. ...

随机推荐

  1. java并发编程_建立概念

    在学习多线程编程时,相信大家会遇到好多概念类的东西,对于这些概念的不准确理解会导致后面越学越糊涂,现将学习过程中遇到的概念整理到这篇博客上,一来记录学习点滴,二来也加深理解,如果有理解不准确的地方,希 ...

  2. 使用laravel的任务调度(定时执行任务)

    laravel中有一个很强大上的功能,只需要在服务器上添加一个cron条目,就可以定时执行所有的laravel任务. 现在有如下数据表: 我想让cron表中的cron字段的值每分钟增加1,那么我需要如 ...

  3. Android 源码编译环境搭建(64位Ubuntu)各种依赖包安装

    1.准备: 普通PC(要求能上网), PC的操作系统Ubuntu 10.04 LTS(64位的),已经下载好的Android 1.6_r1的源代码. 2.Linux的依赖package安装: 为了更快 ...

  4. Eclipse快捷键集结

    Debug快捷键 F5单步调试进入函数内部.   F6单步调试不进入函数内部,如果装了金山词霸2006则要把“取词开关”的快捷键改成其他的.   F7由函数内部返回到调用处.   F8一直执行到下一个 ...

  5. 通过设计让APP变快的6个方法

    我们都知道不管网页还是移动应用,响应速度都是最重要的体验指标之一,并且移动应用的网络环境不稳定,速度的体验显得尤为重要.其实速度优化不仅是程序员的事,设计,也能够让APP变得更快. 1. 后台执行 这 ...

  6. JavaScript中String对象处理HTML标记中文本的方法

    big():创建一个<big></big>标记,将这个字符串的字体变大blink():创建一个<blink></blink>标记,使字符串具有闪烁效果b ...

  7. 那年曾让我哭笑不得抓狂的C语言

    1.关于+=以及-= 这是两个运算符,但你否有过这种经历: int temp; char i ;i<MAX;i++) { ... temp=+; //这里本意是每次循环,temp都自增2,但是却 ...

  8. java属性文件读取,属性修改

    /** * 属性文件读取 * @author bestmata * */ public class CommUtil { private static Logger logger=Logger.get ...

  9. Jtree (节点的渲染+资源管理器)

    我们的还是自定义的Jtree的类: package jtree.customNode; import java.io.File; import javax.swing.JTree; import ja ...

  10. hdu 2818 Building Block (带权并查集,很优美的题目)

    Problem Description John are playing with blocks. There are N blocks ( <= N <= ) numbered ...N ...