非阻塞或异步编程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):
def handle(self):
addr = self.request.getpeername()
print 'Got connection from', addr
server = Server(('', 1234), Handler)
server.serve_forever()
threading服务器:
from SocketServer import TCPServer, ThreadingMixIn, StreamRequestHandler
class Server(ThreadingMixIn, TCPServer): pass
class Handler(StreamRequestHandler):
def handle(self):
addr = self.request.getpeername()
print 'Got connection from', addr
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 in rs:
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:
if disconnected:
print r.getpeername(), 'disconnected'
inputs.remove(r)
else: