`
gashero
  • 浏览: 944067 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

修复flup中threadpool在twisted中运行

阅读更多

 

修复flup中threadpool在twisted中运行的日记

作者: 日期:
gashero
2009-09-04

1   简介

希望在twistd托管模式中运行flup的FastCGI服务器,但是启动以后一直有可以接受连接,但是不接受请求的问题。本文记录修复该问题的过程以及方法。

2   故障描述

twistd托管daemon中的flup可以接受连接,但是不接受请求。

3   调试流程

3.1   flup的源码安装

默认使用egg打包方式放在标准Python模块目录,安装后的看不到源码。所以删除了已经安装的flup,而将解压后的flup源码目录拷贝到Python模块目录了。方便进一步调试。

3.2   确定导入的flup模块范围

只有先确定了导入模块的范围才能更好的定位问题点。而Python的 sys.modules 字典对象展示了所有导入对象。

如下两句在阻塞启动flup服务器之前提供打印所有导入模块的功能:

print 'modules',sys.modules.keys()
print 'flup mod',filter(lambda x:'flup' in x,sys.modules.keys())

如此打印出来的模块还是有诸多干扰,整理一下发现如下flup的模块被导入了:

flup
flup.server
flup.server.flup
flup.server.fcgi
flup.server.fcgi_base
flup.server.threadpool
flup.server.threadedserver

再排除了 flup.server.flup 和顶级没用模块以后目标定位在4个模块中:

flup.server.fcgi
flup.server.fcgi_base
flup.server.threadpool
flup.server.threadedserver

好吧,噩梦来了,以前开发的CDN系统就曾经发现过在twistd的daemon模式中使用threadpool无法启动线程的问题。恐怕这次的主要问题点也在这里。这4个模块总代码量为1635行,还好,还不至于很抓狂。

4   FastCGI服务器启动跟踪

4.1   外部入口

from flup.server import fcgi
server=fcgi.WSGIServer(wsgifunc,bindAddress=('0.0.0.0',8080))
server.run()

4.2   flup.server.fcgi 中的初始化

from flup.server.fcgi_base import BaseFCGIServer,FCGI_RESONDER
from flup.server.threadedserver import ThreadedServer

其中 WSGIServer 继承自 fcgi_base.BaseFCGIServerflup.server.threadedserver.ThreadServer 。其 __init__() 构造函数调用了两个父类的构造函数, BaseFCGIServer 的在前。

4.3   server.run() 流程

调用了 flup.server.fcgi.WSGIServer.run() 函数,其定义中的阻塞部分在:

sock=self._setupSocket()
ret=ThreadedServer.run(self,sock)   #这句阻塞
self._cleanupSocket(sock)
return ret

4.4   threadedserver 模块分析

该模块用于处理多线程服务器的线程部分,而不管FastCGI的处理。也是唯一一处调用了 threadpool 模块的地方。共计175行。

这里对threadpool模块的引用只有3处:

  1. 45行,导入模块:

    from flup.server.threadpool import ThreadPool
    
  2. 54行,初始化时,定义为服务器的线程池对象:

    self._threadPool=ThreadPool(**kw)
    
  3. 97行,生成任务,添加任务到线程池:

    conn=self._jobClass(clientSock,addr,*self._jobArgs)
    if not self._threadPool.addJob(conn,allowQueuing=False):
        clientSock.close()
    

由最后一处调用可见不是几年前郁闷我的那个threadpool模块了,不过相信问题是一样的,就是twistd托管daemon模式时,线程的运行是有问题的。

4.5   fcgi_base 中对thread和threading模块的引用分析

大部分地方是使用了线程锁。而使用了启动线程的地方有一处,MultiplexedConnection类的865行,启动线程:

def _start_request(self,req):
    thread.start_new_thread(req.run,())

实际调试发现如上代码的启动中根本没有创建该类的对象,所以可以排除这里出问题的可能。

至于其他地方使用的锁,就先假设不会出问题吧。

4.6   threadpool 结构分析

该模块一共121行,是flup的作者自己写的,其中只有一个类 ThreadPool ,其包含3个方法:

class ThreadPool(object):
    def __init__(self,minSpare=1,maxSpare=5,maxThreads=sys.maxint)
    def addJob(self,job,allQueuing=True)
    def _worker(self)

虽然引用了thread和threading两个模块,不过任务都比较明晰。启动线程使用 thread.start_new_thread(self._worker,()) ,而threading模块仅用于定义锁 self._lock=threading.Condition()

5   修改尝试

5.1   修改threadpool模块中线程启动方式

以前是使用 thread.start_new_thread 方式启动,尝试修改成threading模块的线程对象方式,以及其守护线程模式:

thrd=threading.Thread(target=self._worker)
thrd.setDaemon(True)
thrd.start()

尝试失败。启动的线程仍然在twistd托管时消失了。

5.2   修改threadpool的实现,改为twisted的线程

使用twisted的线程池的相同接口ThreadPool实现:

class ThreadPool(object):
    """Twisted ThreadPool warpper"""

    def __init__(self,minSpare=1,maxSpare=5,maxThreads=sys.maxint):
        #reactor.suggestThreadPoolSize(maxSpare)
        return

    def addJob(self,job,allowQueuing=True):
        print 'call addjob',repr(job)
        reactor.callInThread(job.run)
        return
#threadpool.ThreadPool=ThreadPool
threadedserver.ThreadPool=ThreadPool

重新尝试启动,因为没有阻塞调用 reactor.run() 的地方,所以线程启动失败。

5.3   修改 threadedserver.ThreadedServer.run ,使得加入reactor的启动

这个主要就是利用twisted的思想,将整个函数切块,涉及到信号操作的部分使用 reactor.callFromThread() 调用,其他部分则使用 reactor.callInThread() 放在线程里执行就可以了。

我为了避免污染flup在site-packages目录中的代码,所以是自己在模块里面写代码,然后导入flup以后替换相关对象的方式实现的。这时将原来函数的代码复制过来,做修改,然后替换。同时需要另外导入一些模块,导入与替换:

import select
import errno
from flup.server.threadedserver import setCloseOnExec
threadedserver.ThreadedServer.run=threadedserver_run

通过这样改造以后 server.run() 就可以由twisted的线程进行托管了。启动代码如下:

server=fcgi.WSGIServer(wsgifunc,bindAddress=(addr,port))
reactor.callInThread(server.run)
application=service.Application('httprpc',uid=uid,gid=gid)

6   总结

通过如上一番对flup的改造,就可以将其运行在twisted托管模式了。由twistd负责捕捉错误输出、打印输出,并且使其运行在daemon模式。很方便。

这样修改以后还存在一点不足,就是在普通运行模式下也要用 reactor.callInThread(server.run) 来运行。这种情况下就没法使用Ctrl+C来终止程序了。而必须使用kill -9才行。

1
0
分享到:
评论

相关推荐

    flup安装包

    flup安装包

    flup3-master包

    在Windows系统上搭建Nginx+Python3+MySQL环境时需要的flup包

    web.py flup

    web.py flup 可以直接使用了。。。 若你已有python环境,直接在包解压放在python目录下即可

    python flup

    收藏 FLUP是python下的一种WSCGI的实现,可以比较容易地与NGINX等HTTP Server进行搭配使用。

    flup-1.0.1

    flup是在使用fastcgi时必须的安装包。

    flup-1.0.1.tar

    python kuangjia cai fast

    flup-1.0.2

    flup: random Python WSGI stuff This Python package is a random collection of WSGI modules I've written. fcgi and publisher have long existed since I became interested in Python web programming a few ...

    Python库 | flup-1.0.3.dev_20110111-py2.7.egg

    资源分类:Python库 所属语言:Python 资源全名:flup-1.0.3.dev_20110111-py2.7.egg 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

    distribute-0.7.3,flup3-master

    python3下运行django1,6不能运行提示需要安装flup,但是flup1.02不能安装在python3下的,需要安装flup3-master,安装flup3-master需要先安装distribute-0.7.3

    flup:节点js中基于终端的TCP聊天服务器和客户端

    Flup是生活在终端中的一个简单的聊天应用程序。 它同时实现了server和client 。 创建该项目是为了学习node.js套接字和net模块。 用法: Usage: index [options] Options: -h, --help output usage information -...

    Windows系统下使用flup搭建Nginx和Python环境的方法

    与Linux下不同的是,nginx在windows下是以一个应用程序的方式运行,而不是以一个服务运行(难怪没人在windows服务器上用nginx) 把刚刚下载好的两个压缩包都解压到C:\nginx\, C:\flup\(目录可自己

    flup-py3-master

    flup-py3-master

    Flup页面「Page Flup」-crx插件

    用鼠标翻页 这个小扩展可以让你节省宝贵的时间。只需安装它,打开您最喜爱的网站,将鼠标移动到左侧,直到停止并点击 - 页面将被抬起。 支持语言:English,русский

    Page Flup-crx插件

    语言:English,русский 用鼠标向上翻页 这个小扩展名可以节省您的宝贵时间。 只需安装它,打开您喜欢的网站,向左移动鼠标直至停止,然后单击-页面将被抬起。

    在Windows系统上搭建Nginx+Python+MySQL环境的教程

    运行nginx.exe后本地打开http://localhost,将会看到欢迎页面,这证明nginx在本地运行良好,如果没有出现欢迎页面,请检查是否有进程占用了80端口。 2 安装flup 下载对应版本的flup,这里下载flup3.x版本,适合...

    flupy:python和shell的流利数据管道

    Flupy实现了用于在python可迭代对象上运行的。 所有松散的方法都返回生成器,并且被懒惰地评估。 这允许表达式在极其有限的内存中转换任意大小的数据。 您可以将flupy看作是轻量级的,0依赖性的,纯Python的替代品...

    berrystats:FlaskJinja2 Web 应用程序报告有关 Raspberry Pi 的各种统计信息

    这是在 Arch 上开发的,但应该可以在任何最新的 Linux 发行版上运行。 需要:Nginx、Python 2、Flask、Jinja 2、Flup 和大约 10MB 的 RAM 截图 主页选项卡:: 系统选项卡: 关于选项卡: 安装 安装依赖: 拱: ...

    yourank:用于评估YouTube视频的简单Web应用程序

    你等级简单的Web应用程序,用于用户评估Youtube视频要求python 2.5或以上web.py(easy_install web.py) flup(easy_install flup)-仅在使用lightppd或apache时需要如何填充数据库使用create_db.py脚本$ python ...

Global site tag (gtag.js) - Google Analytics