python下的事件驱动编程

最近用python写一个网络服务的模拟测试程序,先是用同步socket实现了一个简单的server,后来发现要没法添加定时器来定时处理一些任务,于是网上搜索python的异步事件框架库,发现了gevent。

1. gevent介绍

gevent是一个python的网络库,它使用greenlet轻量级线程,使用libevent实现事件驱动。我写的模拟测试程序只使用了libevent的事件驱动,下面就只介绍下gevent的事件驱动编程。

2. 事件驱动

事件驱动顾名思义,就是通过事件来驱动程序的运行,它主要包括三个部分:事件,事件处理,事件分发。gevent是事件驱动是对libevent的封装,因此它关于上述三个部分的描述也类似于libevent。

gevent的事件驱动处理都在gevent.core模块,主要包含以下类:

  • event(事件)

class gevent.core.event(evtypehandlecallback[arg])

使用callback事件处理回调函数创建一个事件对象。

evtype - 事件类型,EV_READ or EV_WRITE, or EV_SIGNAL

handle - 事件句柄,对于EV_READ和EV_WRITE来说handle是一个socket, 对于EV_SIGNAL来说就是一个信号

callback - 事件发生时回调该函数来对事件进行处理

arg - 可选参数

add([timeout])

调用该方法将事件添加到事件调度器,该函数有一个可选的timeout参数,以秒为单位。设置了该参数后事件timout秒后将被执行。

cancel()

取消事件的调度。

pending

事件的属性,如果事件仍然在事件调度器中等候调度将返回True。

class gevent.core.read_event

 创建一个类型为EV_READ的事件

class gevent.core.write_event

 创建一个类型为EV_READ的事件

class gevent.core.timer

创建一个定时器

class gevent.core.signal

 创建一个信号事件

  • event loop

gevent.core.init()

初始化事件队列

gevent.core.dispatch()

分发事件队列中所有的事件,成功返回0,当没有事件注册时返回1.

gevent.core.loop()

分发队列中所有待处理的事件,只执行一次。成功返回0,没有事件注册时返回1。该函数与dispatch的区别是该函数单趟执行。

3. 开发流程

1. gevent.core.init()

2. 创建事件

3. 添加事件

4. gevent.core.loop()

4. 程序示例

使用gevent实现的echo,同时有一个定时器

from gevent import core
from socket import *
from sys import *

class mon_client_handler:
    def __init__(self, s_fd, addr ):
        self.s_fd = s_fd
        self.addr = addr
        self.r_ev = core.read_event( self.s_fd.fileno(), self.on_read )
        self.w_ev = core.write_event( self.s_fd.fileno(), self.on_write )
        self.t_ev = core.timer( -1, self.on_timeout )
        self.r_buffer = ''
        self.w_buffer = ''

    def on_read(self, ev, ev_type ):
        #print 'on_read'
        #print self.addr
        chunk = self.s_fd.recv(1024)
        print 'read chunk len:', len(chunk)
        self.r_buffer += chunk
        #print 'buffer len:', len(self.r_buffer)
        self.process()
        self.r_ev.add()

    def on_write(self, ev, ev_type ):
        #print self,ev,ev_type
        if len(self.w_buffer) > 0:
            size = self.s_fd.send(self.w_buffer)
            print len(self.w_buffer), size
            self.w_buffer = self.w_buffer[size:]
            if len(self.w_buffer) > 0:
                self.w_ev.add()
    
    def write(self, buf):
        #print 'write', len(buf)
        self.w_buffer += buf
        if len(self.w_buffer) > 0:
            self.w_ev.add()

    def start(self):
        self.r_ev.add()
        self.t_ev.add(10)
        
    def stop(self):
        self.r_ev.cancel()
        self.w_ev.cancel()
        self.t_ev.cancel()
        self.s_fd.close()
        
    def process(self):
        self.write(self.r_buffer)
		self.r_buffer=''
            
    def on_timeout(self):
        print 'timeout...'
        self.t_ev.add(5)
        
class mon_server:
    def __init__(self, port, max_clt):
        self.port = port
        self.max_clt = max_clt
        self.fd = None
        self.event = None
        self.started = False

    def start(self):
        if self.started:
            print 'mon_server alread started!'
            return False
        self.fd = socket(AF_INET, SOCK_STREAM)
        self.fd.bind(('0.0.0.0', self.port))
        self.fd.setblocking(0)
        self.event = core.read_event( self.fd.fileno(), self.on_request )
        self.event.add()
        self.fd.listen(self.max_clt)
        self.clients = []
        return True

    def stop(self):
        self.event.cancel()
        self.fd.close()

    def on_request( self, e, evtype ):
        (clt_fd, addr) = self.fd.accept()
        clt_fd.setblocking(0)
        print 'Connected by', addr
        clt = mon_client_handler( clt_fd, addr )
        self.clients.append(clt)
        clt.start()

def main():
    core.init()
    svr = mon_server( 8888, 1 )
    svr.start()
    core.dispatch()
    print 'Server exit!'

if __name__ == '__main__':
    main()



 


你可能感兴趣的:(python)