诛仙兽神:Twisted的Deffered就是用CPS写Python程序? - cloverprince的恶搞空间 - ItEye技术网站
来源:百度文库 编辑:九乡新闻网 时间:2024/04/26 15:35:40
2009-03-22
链接:http://twistedmatrix.com/
一个示例程序:
这个服务器程接受TCP连接,并将收到的小写字母变成大写:
Python代码
看,我没有显式地使用socket,bind,listen,accept,send,recv,close等等系统调用。Twisted已经帮我做了这些琐碎麻烦,而每个程序都会用到,而且稍有不慎就会出错,而且还因操作系统而异的操作(当然操作系统这一层是Python语言负责屏蔽的)。当然Twisted其实连select和poll都用上了。
总之,我讨厌用socket。Twisted挺方便的。
=== Twisted的异步事件 ===
有些事情不是马上就能做完的。比如发送数据,接收数据。这很麻烦,还涉及到“非阻塞IO”。传统的方法就是用select(或poll)帮我探测哪些文件描述符可读,可写。这样一来整个程序的顺序就混乱了。整个程序必须围绕这个select来写自动机(虽然我是北邮出身,对自动机可是相当的在行,但毕竟C语言不是专业的自动机语言,用SDL或者Erlang语言来编自动机还差不多。)
Twisted引入了Deferred类。这个类的每个实例表示一个不能马上完成的动作。例如:
Python代码
神奇之处就在于,当你获得了Deferred对象的时候,你的数据并没有返回。它“正在等待被完成”。这时候,你不要去等它完成。而是告诉它:“当完成之后,把数据变成大写,然后把大写数据发送出去。”这样,你就不用等待数据到达了。你可以继续响应其他事件。这个被“推迟”的处理交给Twisted去做。
=== CPS是什么? ===
这是函数式编程中常用的伎俩,迫使程序按照一定的顺序求值。比如计算这个算数表达式:
5*8+3*6
究竟是先计算5*8,还是先计算3*6,还是都不计算,直接将两个乘法表达式带入加法呢?
如果这样写:
Python代码
这种风格叫做“Direct Style”。特点是函数值通过返回值返回。
再看另一种罕见的写法:
Python代码
这个叫做“Continuation Passing Style”。也就是,每个函数多带一个参数,这个参数是一个函数,这个函数成为Continuation。当计算完当前函数的值之后,不是直接返回,而是将这个值传入Continuation函数中,作为参数。
最后一句太不直观了。我来解释一下:
最外层:
Python代码
这个函数计算5,8的积,然后将结果传入右边的函数,就是那个lambda p1:...
这个
Python代码
是一个函数,接受一个参数p1。这里p1就是5和8的积。它的返回值是mul(3,6, lambda p2:add(p1,p2,prettyprint)),而其中p1是这个lanbda的参数(p2不是。p2是内层lambda的参数),因此这个(外层)lambda函数的值就是:
Python代码
这又是个mul函数。将3和6相乘,传入右边的函数:lambda p2: add(40,p2,prettyprint),作为参数。既然参数p2是3*6==18,那么,这个lambda函数的值就是
Python代码
然后,算出40+18==58,传入prettyprint作为参数。值就是
Python代码
这个函数打印58,返回Null
完毕。总结:
Python代码
CPS有什么好处?
如上总结:CPS的函数的求值顺序是被用户确定的。这在没有过程化结构的函数式语言中非常重要。有些具有副作用的函数,必须严格控制求值顺序。
CPS有什么坏处?
不直观。不好读。容易出错。
=== Twisted里面的Deferred和CPS有什么关系? ===
看看Twisted自己的例子:
Python代码
这就是说,把CPS的思想带入Deferred里面了。
Deferred就是一个函数,接受另一个函数(Twisted叫它Callback,我叫它Continuation)。这就是指明:得到结果以后,下一步做什么。这不是和CPS一样吗?
=== 后记 ===
我是刚刚开始学Twisted,毕业设计可能用到。但是看到这里让我突然感到特熟悉。难道说以后要在Twisted中大量使用CPS来编程?
等着瞧吧。
Twisted的Deffered就是用CPS写Python程序?
关键字: cps, twisted, 网络, 异步Twisted是个不错的Python网络应用程序框架。可以免去你写Socket的烦恼。链接:http://twistedmatrix.com/
一个示例程序:
这个服务器程接受TCP连接,并将收到的小写字母变成大写:
Python代码
- from twisted.internet.protocol import Protocol,Factory
- from twisted.internet import reactor
- class Echo(Protocol):
- """ 一个Protocol类,负责一个连接。
- Twisted是基于事件的框架。建立连接,收到消息,都会引发事件,由方法处理。 """
- def connectionMade(self):
- self.transport.write("Hello!\r\n")
- self.transport.write("Send in lowercase and I reply in uppercase.\r\n\r\n")
- def dataReceived(self, data):
- self.transport.write(data.upper())
- class EchoFactory(Factory):
- """ 工厂用于实例化Protocol类。一个监听端口需要一个工厂。 """
- protocol = Echo
- reactor.listenTCP(8007, factory) # 监听端口。
- reactor.run() # 这是让Twisted框架进入“消息循环”,不断接受消息,引发事件。
看,我没有显式地使用socket,bind,listen,accept,send,recv,close等等系统调用。Twisted已经帮我做了这些琐碎麻烦,而每个程序都会用到,而且稍有不慎就会出错,而且还因操作系统而异的操作(当然操作系统这一层是Python语言负责屏蔽的)。当然Twisted其实连select和poll都用上了。
总之,我讨厌用socket。Twisted挺方便的。
=== Twisted的异步事件 ===
有些事情不是马上就能做完的。比如发送数据,接收数据。这很麻烦,还涉及到“非阻塞IO”。传统的方法就是用select(或poll)帮我探测哪些文件描述符可读,可写。这样一来整个程序的顺序就混乱了。整个程序必须围绕这个select来写自动机(虽然我是北邮出身,对自动机可是相当的在行,但毕竟C语言不是专业的自动机语言,用SDL或者Erlang语言来编自动机还差不多。)
Twisted引入了Deferred类。这个类的每个实例表示一个不能马上完成的动作。例如:
Python代码
- # data = sock.recv(MAX_LENGTH) # Don't do this! Program will block!!!
- # uppercase_data = data.upper()
- # sock.send(uppercase_data)
- # Do this (Not strict Twisted code. Just for demonstration.)
- deferred_obj = Deferred(sock.recv, MAX_LENGTH) # Instantiate a "Deferred" object
- deferred_obj.addCallback(lambda data: data.upper()) # Tell it what to do when received
- deferred_obj.addCallback(lambda upper_data: sock.send(upper_data)) # And then?
神奇之处就在于,当你获得了Deferred对象的时候,你的数据并没有返回。它“正在等待被完成”。这时候,你不要去等它完成。而是告诉它:“当完成之后,把数据变成大写,然后把大写数据发送出去。”这样,你就不用等待数据到达了。你可以继续响应其他事件。这个被“推迟”的处理交给Twisted去做。
=== CPS是什么? ===
这是函数式编程中常用的伎俩,迫使程序按照一定的顺序求值。比如计算这个算数表达式:
5*8+3*6
究竟是先计算5*8,还是先计算3*6,还是都不计算,直接将两个乘法表达式带入加法呢?
如果这样写:
Python代码
- def add(a,b):
- return a+b
- def mul(a,b):
- return a*b
- def prettyprint(a):
- print a
- prettyprint(add(mul(5,8),mul(3,6)))
这种风格叫做“Direct Style”。特点是函数值通过返回值返回。
再看另一种罕见的写法:
Python代码
- def add(a,b,f): # 这里f是一个函数。add做的事就是算出结果,然后传入f做参数。
- return f(a+b)
- def mul(a,b,f): # 这里f也是一个函数。只不过mul算乘法。
- return f(a*b)
- def prettyprint(a): # prettyprint是唯一不带参数f的函数。
- print a
- return None
- mul(5,8, lambda p1: mul(3,6, lambda p2: add(p1,p2,prettyprint)))
这个叫做“Continuation Passing Style”。也就是,每个函数多带一个参数,这个参数是一个函数,这个函数成为Continuation。当计算完当前函数的值之后,不是直接返回,而是将这个值传入Continuation函数中,作为参数。
最后一句太不直观了。我来解释一下:
最外层:
Python代码
- mul(5,8, lambda p1: .... )
这个函数计算5,8的积,然后将结果传入右边的函数,就是那个lambda p1:...
这个
Python代码
- lambda p1: mul(3,6, lambda p2: add(p1,p2,prettyprint))
是一个函数,接受一个参数p1。这里p1就是5和8的积。它的返回值是mul(3,6, lambda p2:add(p1,p2,prettyprint)),而其中p1是这个lanbda的参数(p2不是。p2是内层lambda的参数),因此这个(外层)lambda函数的值就是:
Python代码
- mul(3,6, lambda p2: add(40,p2,prettyprint)) # 注意p1被代换成40 (40=5*8)
这又是个mul函数。将3和6相乘,传入右边的函数:lambda p2: add(40,p2,prettyprint),作为参数。既然参数p2是3*6==18,那么,这个lambda函数的值就是
Python代码
- add(40,18,prettyprint) # 注意p2被代换成18(18=3*6)
然后,算出40+18==58,传入prettyprint作为参数。值就是
Python代码
- prettyprint(58)
这个函数打印58,返回Null
完毕。总结:
Python代码
- mul(5,8, lambda p1: mul(3,6, lambda p2: add(p1,p2,prettyprint)))
- ==>
- (lambda p1: mul(3,6, lambda p2: add(p1,p2,prettyprint)))(40) # 函数调用
- ==>
- mul(3,6, lambda p2: add(40,p2,prettyprint)) # 注意p1被代换
- ==>
- (lambda p2: add(40,p2,prettyprint))(18) # 函数调用
- ==>
- add(40,18,prettyprint) # 注意p2被代换
- ==>
- prettyprint(58)
- ==>
- 显示58,返回None
CPS有什么好处?
如上总结:CPS的函数的求值顺序是被用户确定的。这在没有过程化结构的函数式语言中非常重要。有些具有副作用的函数,必须严格控制求值顺序。
CPS有什么坏处?
不直观。不好读。容易出错。
=== Twisted里面的Deferred和CPS有什么关系? ===
看看Twisted自己的例子:
Python代码
- # Read username, output from factory interfacing to web, drop connections
- from twisted.internet import protocol, reactor, defer, utils
- from twisted.protocols import basic
- from twisted.web import client
- class FingerProtocol(basic.LineReceiver):
- def lineReceived(self, user):
- # 看到了没有,这里是典型的Continuation Passing Style
- # 提示:getUser返回一个Deferred对象,可以被addCallback和addErrback
- self.factory.getUser(user
- ).addErrback(lambda _: "Internal error in server"
- ).addCallback(lambda m:
- (self.transport.write(m+"\r\n"),
- self.transport.loseConnection()))
- class FingerFactory(protocol.ServerFactory):
- protocol = FingerProtocol
- def __init__(self, prefix): self.prefix=prefix
- def getUser(self, user):
- return client.getPage(self.prefix+user)
- reactor.listenTCP(1079, FingerFactory(prefix='http://en.wikipedia.org/wiki/')) # 我改的,原来的网址访问不同。忽略吧,和主题无关。
- reactor.run()
这就是说,把CPS的思想带入Deferred里面了。
Deferred就是一个函数,接受另一个函数(Twisted叫它Callback,我叫它Continuation)。这就是指明:得到结果以后,下一步做什么。这不是和CPS一样吗?
=== 后记 ===
我是刚刚开始学Twisted,毕业设计可能用到。但是看到这里让我突然感到特熟悉。难道说以后要在Twisted中大量使用CPS来编程?
等着瞧吧。
Twisted的Deffered就是用CPS写Python程序? - cloverprince的恶搞空间 - ItEye技术网站
恶搞夫妻玩的就是创意!
个人对程序员的理解 - - ItEye技术网站
网景和微软的竞争 - - ITeye技术网站
浅谈JSON的两种数据结构 - - ITeye技术网站
恶搞夫妻玩的就是创意(荐)!
在中国,搞技术的就是X
在中国,搞技术的就是狗!
原来公司需要这样的你 - 淡蓝的意大利 - ItEye技术网站
优秀的孩子是这样培养的,建议永久保存 - 微乎其微 神乎其神 - ITeye技术网站
一个Java架构师的新年期望 - 花钱的年华 - ITeye技术网站
sun(Java)与微软的故事 - what life tells - ITeye技术网站
软件测试外包揭秘 - 我是一个二手的程序员! - ITeye技术网站
Java-Web开发基础之html语法基础 - 小雄的博客 - ITeye技术网站
转:再见了,已走上陌路的爱 - 心似海 - ITeye技术网站
iBATIS 模糊查询LIKE (转) - 我的博客 - ITeye技术网站
恶搞技术
惊心动魄的恶搞瞬间
经不起恶搞的天皇
恶搞的脑筋急转弯
老外没心没肺的恶搞
惊心动魄的恶搞瞬间
(转帖)在中国,搞技术的就是狗! -
Oracle学习路线图 - zscomehuyue - ItEye技术网站