python开启多个端口服务_python bottle使用多个端口(多个进程)提高并发
我的程序是用python結(jié)合bottle框架寫的,但bottle自帶wsgi原本只是單進(jìn)程單線程運(yùn)行模式(Bottle 默認(rèn)運(yùn)行在內(nèi)置的 wsgiref 服務(wù)器上面。這個(gè)單線程的 HTTP 服務(wù)器在開發(fā)的時(shí)候特別有用,但其性能低下,在服務(wù)器負(fù)載不斷增加的時(shí)候也許會(huì)是性能瓶頸, 一次只能響應(yīng)一個(gè)請(qǐng)求)。為了提升程序的處理能力,首先要啟用多線程,即在程序中使用gevent( 大多數(shù)服務(wù)器的線程池都限制了線程池中線程的數(shù)量,避免創(chuàng)建和切換線程的代價(jià)。盡管和進(jìn)程 (fork)比起來,線程還是挺便宜的。但是也沒便宜到可以接受為每一個(gè)請(qǐng)求創(chuàng)建一個(gè)線程。gevent 模塊添加了 greenlet 的支持。 greenlet 和傳統(tǒng)的線程類似,但其創(chuàng)建只需消耗很少的資源。基于 gevent 的服務(wù)器可以生成成千上萬的 greenlet,為每個(gè)連接分配一個(gè) greenlet 也毫無壓力。阻塞greenlet,也不會(huì)影響到服務(wù)器接受新的請(qǐng)求。同時(shí)處理的連接數(shù)理論上是沒有限制的。)。只需要在run中加上 server=‘gevent‘,如下:
1 importgevent
2 from gevent importmonkey.patch_all()
3 代碼段……
4 run(host=‘0.0.0.0‘, port=8080, server=‘gevent‘)
盡管使用了多線程模式,但這些線程都是跑在一個(gè)進(jìn)程里,所以需要開啟多個(gè)進(jìn)程來進(jìn)一步提升并發(fā)處理能力,因此在啟用腳本的時(shí)候,在run(port=)里,端口號(hào)不能寫死,應(yīng)該使用變量來傳遞,如下代碼(在腳本執(zhí)行時(shí),在需帶一個(gè)參數(shù),這個(gè)參數(shù)是大于1024的整數(shù),否則報(bào)錯(cuò)停止腳本):
importgevent,sys
from gevent importmonkey.patch_all()
#獲取端口號(hào)
try:
portnum = int(sys.argv[1])
exceptException,e:
print "請(qǐng)帶上整數(shù)類型的端口號(hào)啟動(dòng)此程序"logging.error("請(qǐng)帶上整數(shù)類型的端口號(hào)啟動(dòng)此程序")
sys.exit(1)
if portnum <= 1024:
print "端口號(hào)請(qǐng)大于1024!"logging.error("端口號(hào)請(qǐng)大于1024!")
sys.exit(1)
代碼段……
run(host=‘0.0.0.0‘, port=portnum , server=‘gevent‘)
執(zhí)行方式如下(osyw.py是我python程序名):
python osyw.py 1124
如果純靠手動(dòng)操作這些,在生產(chǎn)上,很不方便,所以我寫了個(gè)shell來管理,這個(gè)shell定義了多個(gè)端口號(hào),然后去循環(huán)啟用或停止python進(jìn)程,腳本大概如下(是用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) #設(shè)置了3個(gè)端口
#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
elseaction "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
elseaction "osyw ${i} stop ..." /bin/false
fi
rm -f ${pidfile}
elseaction "osyw ${i} Has stopped !" /bin/false
fi
done
}
# See how we were called.
case "$1" instart)
start
;;
stop)
stop
;;
status)
status -p ${pidfile} ‘osyw‘RETVAL=$?
;;
restart)
stop
sleep 2start
;;
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=2esac
exit $RETVAL
效果圖:
本人的代碼是用svn管理的,所以上傳代碼后,SVN鉤子會(huì)調(diào)用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
當(dāng)然,為了結(jié)合shell,python程序里也要做一些處理,如自動(dòng)把程序轉(zhuǎn)為后臺(tái)守護(hù)進(jìn)程,然后把進(jìn)程ID寫入文件,以下是關(guān)鍵的python代碼:
#定義PID路徑
pid_path = ‘/var/run/osyw_%s.pid‘ %portnum
defdaemonize():
"""把本腳本轉(zhuǎn)為守護(hù)進(jìn)程"""
try:
pid=os.fork()
if pid>0:
sys.exit(0)
exceptException,e:
logging.error(e)
sys.exit(1)
os.chdir(‘/‘)
os.umask(0)
os.setsid()
try:
pid=os.fork()
if pid>0:
sys.exit(0)
exceptException,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 #導(dǎo)入配置文件
if setting.status == ‘online‘: #如果配置中是線上的,則程序轉(zhuǎn)入后臺(tái)運(yùn)行
daemonize()
exceptException:
passapp =default_app()
app = SessionMiddleware(app, session_opts) #sessionMiddleware是session插件
run(app=app,host=‘0.0.0.0‘, port=portnum,server=‘gevent‘)
最好,用nginx代理來負(fù)載這些端口,我nginx和python程序是安裝在同一臺(tái)服務(wù)器上的:
以上是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;
}
做完這些后,當(dāng)訪問80端口時(shí),nginx就會(huì)平均輪洵分配到每個(gè)端口上去,實(shí)現(xiàn)了多進(jìn)程,多線程的運(yùn)行模式,更有效的提升了并發(fā)處理能力
原文:http://www.cnblogs.com/drfdai/p/4518121.html
總結(jié)
以上是生活随笔為你收集整理的python开启多个端口服务_python bottle使用多个端口(多个进程)提高并发的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php抓取带帐号密码,PHP实现抓取迅雷
- 下一篇: python中dict转换成list_p