Archive for April 23rd, 2008

Python的产品环境部署

Wednesday, April 23rd, 2008

Python的产品环境部署

作者: gashero

目录

1   Python的版本及安装

产品环境最常用的Python运行环境是Python 2.4.x系列,至今最新版本是2.4.4。而Centos4.x默认附带的Python为2.3.x系列,不支持某些Python2.4.x的功能和第三方插件。需要重新安装。

1.1   Python 2.4.4的安装

首先得到Python2.4.4的安装包 Python-2.4.4.tar.bz2 ,解压/编译/安装的步骤与一般的tarball方式相同:

$ su
# tar xjvf Python-2.4.4.tar.bz2
# cd Python-2.4.4
# ./configure
# make
# make install

这样的过程最终会把Python安装到 /usr/local/bin 下。

1.2   修改选择的Python版本

经过这样的编译安装之后,系统中会同时有两个版本的Python存在。默认情况下,会使用新安装的Python-2.4.4。不过对于某些运行方 式,如crontab,则会调用旧版本的。所以应该删除所有python->python2.3的符号链接,并且建立python2.4-> python的符号链接。如果有直接命名为python的Python2.3版本,那么直接删除即可。

查找所有可以被$PATH索引到的Python可执行文件版本:

$ whereis python

2   安装普通的Python第三方模块

一般的纯Python第三方模块的安装过程如下,假设模块名称为 XXX-x.y.z.tar.gz

$ tar xzvf XXX-x.y.z.tar.gz
$ cd XXX-x.y.z
$ su
# python setup.py install
... ...
# exit
$ python
>>> import XXX
>>>

如上过程已包含测试,即模块的导入成功。

3   安装特别的扩展模块

有些特别的扩展模块需要特别的安装方式。

3.1   MySQLdb

Python连接MySQL数据库的扩展模块。需要在机器上已经安装了MySQL的客户端开发包,包含已经安装的源码。Python还需要可以找到MySQL客户端的配置时(configure)的配置文件。

安装过程如下(已忽略解压缩过程):

# python setup.py config
# python setup.py build
# python setup.py install

4   通过 easy_install 安装扩展模块

这是PEAK开发的新的Python扩展包方式,使用方式还不是很广泛,但是有些模块必须使用他来安装。比如 MySQLdb-1.2.2 ,在使用相同的安装命令时,内部就会调用 easy_install 来安装。

安装命令与默认的方式相同。

另一种安装方式:先下载 easy_install 然后通过他在线安装Python扩展模块,有如ubuntu的apt-get安装方式,不需要先下载好模块的文件。这种方式需要先下载 ez_setup.py ,地址如下 http://peak.telecommunity.com/dist/ez_setup.py

下载后执行该模块即可在线安装最新版本的 easy_install

# python ez_setup.py

通过这种方式就安装成功了 easy_install ,之后可用如下方式安装扩展模块 XXX

# easy_install XXX

比如安装MySQLdb:

# easy_install MySQLdb

一般不推荐使用这种方式安装,因为所有的模块都是必须在线安装,产品环境的很多服务器是不允许上网的。另外,这种方式并不方便控制需要安装的模块的版本。这种版本差异可能是致命的,所以必须非常严格的控制。

StacklessPython简要笔记

Wednesday, April 23rd, 2008

StacklessPython简要笔记

作者: gashero

目录

1   微进程tasklet

stackless的基本构成单元,一种可调度对象。

1.1   建立微进程对象

示例:

import stackless
def print_x(x):
    print x

stackless.tasklet(print_x)('one')
stackless.run()

微进程建立后并不运行,直到调用 stackless.run() 才开始运行。

1.2   调度

微进程执行的函数内部可以调用 stackless.schedule() 来暂停当前微进程而把执行权交给执行队列的下一个微进程。

这也是在stackless中实现协程的基本方式。

1.3   轻量级进程

class HackySacker:
    def __init__(self):
        #todo...
        self.channel=stackless.channel()
        stackless.tasklet(self.messageLoop)()
    def messageLoop(self):
        while True:
            message=self.channel.receive()
            if message=='exit':
                return
            #todo...
            stackless.schedule()    #这里注意要调度一下

执行速度比线程的更快,而且可以允许10000个微进程而不死掉。

2   通道channel

用于微进程之间传递信息和控制微进程的运行流程。可以替代传统线程程序中的Queue模块的互斥队列。

2.1   交换信息

示例:

import stackless
channel=stackless.channel()
def recv_tasklet():
    msg=channel.receive()
    print msg
def send_tasklet():
    channel.send('hello')

调用 channel.receive() 时会阻塞当前微进程,等待消息到来。调用 channel.send() 时也会阻塞,直到有微进程读取了消息。

2.2   任务分发

如果一个入口微进程将消息源源不断的发送到通道,而多个工作者微进程等待接受消息,那么每个消息只能被一个微进程所接受,而不是被所有接受。

2.3   事件管理器

使用channel实现的一个基类,用于事件的等待与处理。

class EventHandler:
    def __init__(self,*outputs):
        if outputs==None:
            self.outputs=[]
        else:
            self.outputs=list(outputs)
        self.channel=stackless.channel()
        stackless.tasklet(self.listen)()
    def listen(self):
        while True:
            val=self.channel.receive()
            self.processMessage(val)
            for output in self.outputs:
                self.notify(output)
    def processMessage(self,val):
        pass
    def notify(self,output):
        pass
    def registerOutput(self,output):
        self.outputs.append(output)
    def __call__(self,val):
        self.channel.send(val)

功能:

  1. 通过 listen 方法,持续的监听通道上传来的消息。
  2. 通过 processMessage 处理收到的消息。
  3. 通过 notify 方法将收到的结果发送到输出端。
  4. registerOutput 可以添加新加的输出端。
  5. __call__ 可以方便的用对象后加参数来给它发消息。

3   协程coroutine

使用通道实现,两个函数都在循环中等待对方发来的消息。

3.1   乒乓球的例子

import stackless
ping_channel=stackless.channel()
pong_channel=stackless.channel()
def ping():
    while ping_channel.receive():   #在此阻塞
        #todo...
        pong_channel.send('from ping')
def pong():
    while pong_channle.receive():
        #todo...
        ping_channel.send('from pong')
stackless.tasklet(ping)()
stackless.tasklet(pong)()
stackless.tasklet(ping_channel.send)('startup') #启动循环的微进程
stackless.run()