非阻塞或异步编程python

来源:互联网 发布:java开发职位描述 编辑:程序博客网 时间:2024/06/08 15:56

非阻塞或异步编程python

例如,对于一个聊天室来说,因为有多个连接需要同时被处理,所以很显然,阻塞或同步的方法是不合适的,
这就像买票只开了一个窗口,佷多人排队等一样。
那么我们如何解决这个问题呢?
主要有三种方法:
   forking、
   threading、
   异步I/O。
   
Forking和threading的方法非常简单,通过使用SocketServer服务类的min-in类就可以实现。forking只适用于类Unix平台;threading需要注意内存共享的问题。

异步I/O如果底层的方法来实现是有点困难的。
要简单点,我们可以考虑使用标准库中的框架或Twisted
(Twisted是一个非常强大的异步网络编程的框架)。

一、用ScoketServer实现Forking和threading

下面我们使用两个例子来分别创建forking服务器和threading服务器。

Forking 服务器:

from SocketServer import TCPServer, ForkingMixIn,StreamRequestHandler

class Server(ForkingMixIn, TCPServer): pass

class Handler(StreamRequestHandler):
    defhandle(self):
       addr = self.request.getpeername()
       print 'Got connection from', addr
       self.wfile.write('Thank you for connecting')

server = Server(('', 1234), Handler)
server.serve_forever()

threading服务器:

from SocketServer import TCPServer, ThreadingMixIn,StreamRequestHandler

class Server(ThreadingMixIn, TCPServer): pass

class Handler(StreamRequestHandler):
    defhandle(self):
       addr = self.request.getpeername()
       print 'Got connection from', addr
       self.wfile.write('Thank you for connecting')

server = Server(('', 1234), Handler)
server.serve_forever()

二、使用select实现异步I/O

所谓异步I/O,打个比方,就是如果一大群人都想你听他说话,那么你就给他们每人一分钟的时间说,大家轮流说,没说完的待会儿轮到时再继续说。也就是一个时间片的方法。

要实现异步I/O,我们可以通过使用框架asyncore/asynchat或Twisted,它们都是基于select函数或poll函数(poll只适于类Unix系统)的。select和poll函数都来自select模块。

select函数要求三个必须序列作为参数和一个可选的以秒为单位的超时值。序列中是表示文件描述符的整数值,它们是我们要等待的连接。这三个序列是关于输入、输出和异常条件的。如果超时值没有给出的话,select将处于阻塞状态(也就是等待)直到有文件描述符准备动作。如果超时值给出了,那么select只阻塞给定的时间。如果超时值是0的话,那么将不阻塞。select返回的值是一个由三个序列组成的元组,它们分别代表相应参数的活动的子集。例如,第一个序列返回的是用于读的输入文件描述符构成的序列。

序列可以包含文件对象(不适于Windows)或socket。下面这个例子创建一个使用select去服务几个连接的服务器(注意:服务端的socket自身也提供给了select,以便于它能够在有新的连接准备接受时发出信号通知)。这个服务器只是简单地打印接受自客户端的数据。你可以使用telnet(或写一个基于socket的简单的客户端)来连接测试它。

select server

import socket, select

s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host, port))

s.listen(5)
inputs = [s]
while True:
    rs, ws, es =select.select(inputs, [], [])
    for r inrs:
       if r is s:
           c, addr = s.accept()
           print 'Got connection from', addr
           inputs.append(c)
       else:
           try:
               data = r.recv(1024)
               disconnected = not data
           except socket.error:
               disconnected = True

           if disconnected:
               print r.getpeername(), 'disconnected'
               inputs.remove(r)
           else:
               print data

体验新版博客
原创粉丝点击