天天看点

继续谈谈Twisted

那我就来继续随便谈谈twisted

首先讨论一下, 为什么需要twisted, 需要异步

为了更高效的利用cpu和资源, 提高用户的相应速度

任务需要较长时间才能完成分成两种情况,

1) 计算量较大, 需要cpu算好久才能算出来, 自然算出来才能给结果, 称为cpu等待.

2) 需要等待其他的数据, 比如需要从服务器等待获取信息, 需要从数据库等待查询结果, 这种虽然自己很闲, 无事可做, 但不得不干等, 称为i/o等待.

cpu等待是没办法的, 就是要算那么长时间, 唯一能做的是为了让用户体验好些, 大家轮流占用cpu, 这种典型的方法就是多线程...

i/o等待是应该需要优化的, 这是干等白白浪费并占住了资源, 使得其他用户也无法使用. 这儿就需要异步, 需要twisted, 需要callback.

本来我要等待数据, 然后程序才能继续, 异步的做法是, 把后续的处理程序封装成callback, errback, 把等待数据ready封装成event (让系统调用select去侦听数据i/o). 这样主程序不需要去专门等待某一个event, 有event触发就处理, 这就达到异步的效果.

所以在判断是否需要使用异步, 该不该使用twisted时, 只需要考虑是否存在i/o等待, 只要有i/o等待就应该考虑使用异步.

而twisted的代码无论多么复杂, 其实都是在做如下这样简单的事情,

通过定义protocal和factory来解析请求

通过定义callback来处理请求

定义i/o connection (将factory作为参数, 包含protocal和callback), 并加到event loop(reactor)中去

run reactor

再来, twisted主要应用于什么场景, 使用twisted真的比直接使用socket方便合理吗

twisted主要用于开发server, 它就是为此而生的

下面我们通过简单的例子来和socket对比一下,

下面我们先来看一下客户端, 建立一个链接, 发送多条message

先来看看socket的server, 显然这段代码只能接收到第一条message

如果需要接受所有的message, 必须在conn.recv前加上while, 这样保证接收到所有message后才去accept新的connection.

如果同时打开多个client, 那么这儿必须先接收完第一个client的所有message, 才能开始接收第二个client的...

这样就block了, 用户就不爽了...

再来看看用twisted实现的server, 可以试试同时打开多个上面的client, 该server是可以同时并发接收每个client的数据的, 而不是需要处理完一个client, 才开始处理下一个. 所以确实用twisted开发server比直接使用socket方便合理许多.

想想twisted是怎么样实现这种异步的, 是怎么样保存各个connection并在之间自由切换的?

从头开始, 大家先简单把i/o想象成文件, 对于操作系统而言, i/o操作就等同于对文件的读写操作, 其他对系统是透明的.

对于一个twisted server, 刚开始监听一个i/o端口(这儿可以想象对于twisted有个侦听队列, 刚开始list中只有一个port), 等待请求...

请求到达(相当于conn, addr = sock.accept() ), 触发connectionmade event, 并把该connection加到侦听队列.

某connection收到数据, 触发datareceived event

某connection closed, 触发connectionlost event, 并把该connection从侦听队列中删除.

如果在某个callback, 如datareceived中出现一个很耗时的任务时该怎么办, 比如需要从另外一个服务器获取数据.

异步中, callback使用的第一原则是, 不能block, 因为主线程一旦block, 啥事就都做不了

所以这儿必须要再次使用异步, 在callback中再次设置event和callback, 并将和远程服务器的connection加到侦听队列中.

本文章摘自博客园,原文发布日期:2011-11-12