第二部分:slow poetry and the apocalypse

原文:http://krondo.com/blog/?p=1247
作者:dave
译者:notedit
时间:2011.05.19

我的假设

我假设你已经有一些基本的能力去写python程序,并且直到一些socket编程方面的额知识,如果你没有接触过socket请移步这里 socket module documention, 这个系列中的代码例子都是运行在python2.5 和twisted 8.2.0,程序如果不能正确运行请检查你的python和twisted 的版本.

获取例子代码

你可以在public git repository获取例子代码,如果你可以用git 或者其他的版本管理软件,你可以直接clone 出一份代码:

git clone git://github.com/jdavisp3/twisted-intro.git

缓慢的诗
尽管cpu比网络要快很多,但是网络还是仍旧会比你的脑袋或者眼睛快.所以你要看到cpu-network是怎样运行几乎是不可能的.我们需要的是一个slow server,可以让我们的眼睛看到变化.既然是一个server,那就让我们的server来生产两首颇具诗意的诗吧,在代码仓库的子目录中有John Donne, W.B. Yeats, 和 Edgar Allen Poe 的三首小诗,当然如果换成你自己写的,that will be nice
最基本的”poetry server” 的实现在 blocking-server/slowpoetry.py,你可以让他跑起来:

python blocking-server/slowpoetry.py poetry/ecstasy.txt

上面这个命令会开启一个阻塞的服务器,你可以打开这个阻塞服务器的源码看一下,你可以看到我们并没有用到twisted,只有一些简单的socket 操作.它可以在每个固定的延迟后发出固定的数量的字节,默认的它会每0.1s 发出10个字节.你可以通过–num-bytes 和 –delay 来控制时间和字节数,比如下面:

python blocking-server/slowpoetry.py --num-bytes 50 --delay 5 poetry/ecstasy.txt

当这个服务开始运行的时候,它会打印出它监听的端口.默认的,这个是一个随机的端口,你可以通过修改配置让它监听固定的端口,你可以指定它监听的端口如下:

python blocking-server/slowpoetry.py --port 10000 poetry/ecstasy.txt

如果你有netcat 命令的话,你可以测试这个server 通过一下的命令:

netcat localhost 10000

如果一切正常的话,你会看到一条小诗被每次输出一些字节,一旦这首小诗被完全生产出来,服务器会断开连接.

如果你看源码的话你会发现,poetry server 不仅仅是每次输出一些字节,如果你再用其他的client去连接server 的话,其他的client 必须等到第一个client被处理完才会被poetry server 处理. 现在的poetry server 确实很慢啊,慢的我蛋痛.

阻塞的client
在我们的例子中我们的客户端也是阻塞的,它可以从多个server 上一个接一个的读取内容,现在我们给我们的客户端三个任务去执行,就想图片一中的那样.首先我们先启动三个服务器,为三个不同的客户端来服务,如下:


python blocking-server/slowpoetry.py --port 10000 poetry/ecstasy.txt --num-bytes 30
python blocking-server/slowpoetry.py --port 10001 poetry/fascination.txt
python blocking-server/slowpoetry.py --port 10002 poetry/science.txt

接下来我们可以开启阻塞的客户端blocking-client/get-poetry.py来接收小诗了:

python blocking-client/get-poetry.py 10000 10001 10002

客户端会按照顺序的去接收小诗,只有接收完一个才会去接收下一个.你会看到一下的输出:

Task 1: get poetry from: 127.0.0.1:10000
Task 1: got 3003 bytes of poetry from 127.0.0.1:10000 in 0:00:10.126361
Task 2: get poetry from: 127.0.0.1:10001
Task 2: got 623 bytes of poetry from 127.0.0.1:10001 in 0:00:06.321777
Task 3: get poetry from: 127.0.0.1:10002
Task 3: got 653 bytes of poetry from 127.0.0.1:10002 in 0:00:06.617523
Got 3 poems in 0:00:23.065661

基本上就是图片一的文字版本.你可以看一下源代码去定位一下在接收和发送字节的时候那些地方会产生阻塞.

异步的client
下面让我们看看一个简单的异步的client,没有用twisted.先让我们运行一下, async-client/get-poetry.py:


python async-client/get-poetry.py 10000 10001 10002

你将会得到如下的输出:

Task 1: got 30 bytes of poetry from 127.0.0.1:10000
Task 2: got 10 bytes of poetry from 127.0.0.1:10001
Task 3: got 10 bytes of poetry from 127.0.0.1:10002
Task 1: got 30 bytes of poetry from 127.0.0.1:10000
Task 2: got 10 bytes of poetry from 127.0.0.1:10001
...
Task 1: 3003 bytes of poetry
Task 2: 623 bytes of poetry
Task 3: 653 bytes of poetry
Got 3 poems in 0:00:10.133169

这一次的输出结果会比较长因为每当异步的client 每一次从任何一个服务器上获取一些东西都会输出.注意,这个异步的client 会交错的执行三个任务,就像在图片三中描述的那样.

需要注意的是,异步客户端完成任务用了差不多10s,而同步的客户端需要差不多23s,现在回想一下图片三和图片四的区别.通过减少阻塞的时间,我们的异步客户端需要更少的时间.我们的异步的客户端也是会有一些阻塞,但通过交错任务来执行可以减少很多阻塞的时间.

严格的来说,我们的异步client也在执行阻塞操作:它会向stdout输出一些内容.但对我们的例子还没有太大的影响.终端其实一直在准备接收更多的print 的输出,所以print 并不会阻塞,和我们的slow 服务器来说,print语句很快.如果我们的异步程序是一个进程中管道的一部分,在处理标准的输入和输出的时候应该考虑用异步的I/O.twisted 已经提供了在处理标准输入输出时异步I/O 的支持,为了kiss 原则,这里先不用

更进一步的
让我们看一下异步client 的代码,注意异步client代码和同步client代码的区别:

  1. 异步的client会一次连接多个server,而同步的client一次只连接一个server
  2. 异步的client中的socket 通过setblocking(0)设置为了非阻塞的
  3. select 模块的selsect可以用来监听是否有socket可以提供给client 的数据
  4. 从服务器读数据的时候,异步client会尽可能的多读数据直到这个socket被阻塞,然后如果有其他的socket是可读的话就转到下一个,这意味着我们必须要记录每一首小诗传输状态

这个异步client 中最核心的部分是get_poetry 函数的上层的事件循环,这个循环要经过一下的过程:

  1. 用select监听所有打开的sockets,直到其中的一个socket有数据流可以读
  2. 如果有一个socket有数据可读,读取它
  3. 重复循环,直到所有的socket都关闭

同步的client在main 函数中也有一个循环,但是每次遍历的时候同步客户端只下载同一首小诗,直到这首小诗读完.而异步的client在每次循环的时候会读取多个小诗的片段,我们不确定在一次循环中他会读取几个小诗,或者每次读取多少字节, 这完全依赖于服务器的速度以及网络的速度.我们让select 告诉我们哪一个socket有数据可以读,然后我们就可以在不产生阻塞的情况下尽可能多的去读数据了.

假如一个同步的client一直连在一个相同的服务器上(让我们假设是三号服务器),它现在根本不需要一个外部的循环,因为get_poety函数是阻塞的,客户端会一直连在同一个server上,直到获取完整个的一首诗.而异步的客户端没有一个事件循环的话则无法进行下去,异步的客户端需要在一开始的就监听全部的socket,然后在每一次的循环中处理所能收受的所有数据.

这种用一个循环去等待事件的发生,然后去处理事件的模式我们很常见,已经形成了一种设计模式叫做:reactor pattern(反应堆模式),下面这张图比较直观的描述了反应堆模式

这个循环就是一个反应器因为他在不断的等待事件的发生然后响应他们,因为这个原因也被叫做事件循环.因为”反应器”系统总是等待I/O,这些循环有时也被叫做 select loops,select call 也经常等待I/O. 在一个select loop 中,一个事件就是其中一个socket 变为可读的或者可写的.记住 select 不是等待I/O 的唯一的方法,还有其他的方法被用做等待I/O(比如epoll),他们甚至比select 的性能要好,抛开性能不说,他们都用来做同一件事情:监听一些端口,然后等待其中的一些端口可以读或者可以写.

用select来监测文件描述符来实现一个简单的非阻塞程序是可能的,在" 反应器系统中"执行一些不涉及I/O的操作也是可以的.但是在一个真正的反应器系统中,所有的工作都是I/O相关的

严格的来,咱们的异步client 不是” 反应堆模式”,因为循环的逻辑和也业务逻辑没有完全分开,他们交错在一起.一个真正的反应器模式应该让事件循环作为一个抽象来实现以下两点:

  1. 1,接收一些你要处理I/O的文件描述符
  2. 2,当任何一个文件可以读或者可以写的时候,独立的告诉你

一个非常好的反应堆模式还应实现:

  1. 可以处理各种操作系统各种奇怪的实现
  2. 提供一个非常好的抽象的实现去帮助你很容易的去应用reactor
  3. 提供各种公开的协议的实现

好吧,其实我们想说的就是twisted,一个具有鲁棒性很强,跨平台的,包罗万象的反应器模式的实现.第三部分我们将开始写一些简单的twisted 代码了.ARE YOU READY?

转载于:https://www.cnblogs.com/zhangjing0502/archive/2012/05/18/2507816.html

twisted系列教程二–缓慢的诗相关推荐

  1. python twisted教程 二:缓慢的诗

    我的假设 我假设你已经有一些基本的能力去写python程序,并且直到一些socket编程方面的额知识,如果你没有接触过socket请移步这里 socket module documention, 这个 ...

  2. twisted系列教程八–延迟的诗

    Client 4.0 既然我们已经对deferred有些了解了,我们可以用deferred 来重写我们的poetry client,你可以在这里找到client 4.0 twisted-client- ...

  3. 黄聪:Microsoft Enterprise Library 5.0 系列教程(二) Cryptography Application Block (高级)

    原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(二) Cryptography Application Block (高级) 本章介绍的是企业库加密应用程序模块 ...

  4. C#微信公众号开发系列教程二(新手接入指南)

    此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可直接跳过,也欢迎大神吐槽. 微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教 ...

  5. QT5系列教程二---基于qcustomplot的QT5 GUI串口收发绘图软件实现

    QT5系列教程二---基于qcustomplot的QT5 GUI串口收发绘图软件实现 结构 UI部分 代码部分 step1:实现串口数据接受 串口接受数据格式 在`.pro`文件中添加`serialp ...

  6. 以太坊构建DApps系列教程(二):构建TNS代币

    在本系列关于使用以太坊构建DApps教程的第1部分中,我们引导大家做了两个版本的本地区块链进行开发:一个Ganache版本和一个完整的私有PoA版本. 在这一部分中,我们将深入研究并构建我们的TNS代 ...

  7. Cocoapods系列教程(二)——开源主义接班人

    原文地址:Cocoapods系列教程(二)--开源主义接班人 引言 在写该博客的时候,博主刚看到一个问题:"那些头衔只是看起来很厉害,实际不难获得?".然后有个神回复写到:&quo ...

  8. 汇川技术小型PLC梯形图编程系列教程(二):AutoShop软件使用技巧介绍

    原文链接:汇川技术小型PLC梯形图编程系列教程(二):AutoShop软件使用技巧介绍 俗话说的好,磨刀不误砍柴工.这里的刀指的是准备工作:手册+熟练使用软件(掌握一些技巧).所以本篇为大家简单介绍一 ...

  9. 2021年淘宝客系列教程(二)事前准备

    2021年淘宝客系列教程(二)事前准备 本系列立志于将淘宝客如何在微信公众号/微信机器人这类基础上运作,到最后开发一个完整的淘宝客系统而编写,如有雷同,纯属借鉴~ 2021年淘宝客系列教程(一)淘宝客 ...

  10. Altium designer18系列教程二 原理图库制作

    Altium designer18系列教程二 原理图库制作 制作原理图库 一.新建原理图库文件(教程一中有提到) 二.界面介绍 三.画原理图库元器件 在前面的教程中主要讲了讲AD18的优点和AD18的 ...

最新文章

  1. 利用Windows自带服务架设免费邮件服务器
  2. linux python保存mp4
  3. 天才少年何恺明:高考状元的开挂人生
  4. 使用Spring Boot和DJL进行深度学习
  5. LeetCode 1799. N 次操作后的最大分数和(回溯 / 状态压缩DP)
  6. 清除故障,Windows2003更加亲切
  7. 线程同步 -事件Event、临界区对象CriticalSection
  8. apulSoft apShaper for Mac(滤波失真插件)
  9. zoj 2966 Build The Electric System
  10. linux编译生成动态库、静态库,以及使用
  11. ArcGIS中通过JPG图片文件提取矢量要素
  12. 激活剂、天梯与火石:从ASC 19解读产学结合的关键密码
  13. 华为如何显示我的电脑连接到服务器地址,怎么查电脑的服务器连接地址
  14. kubeadm集群化部署多master节点(生产环境适用)
  15. P2【商业级MMORPG大型网游】Unity全栈开发 笔记
  16. 计算机桌面下方标图,电脑下方怎么设置显示桌面图标
  17. python中的self
  18. JavaWeb: Tomcat优化
  19. linux下配置调试debug
  20. 132、网管型和非网管型交换机有什么区别

热门文章

  1. 数据分析工作常见的七种错误及规避技巧
  2. 【Nowcoder - 5670 B Graph】2020 牛客暑期多校训练营(第五场)【最小异或生成树、Boruvka 思想】
  3. 【POJ 2104】【主席树模板题】K-th Number
  4. 使用DWN在Docker中进行渗透测试
  5. Elpscrk:功能强大的智能字典生成器
  6. 343.整数拆分(力扣leetcode) 博主可答疑该问题
  7. linux6的关机快捷键是,LINUX关机快捷键是什么?
  8. cf406E Hamming Triples (推公式)
  9. python 3.X中打包二进制数据存储字符串出错原因分析
  10. MVC3开发常常遇到的问题及常常使用到的代码片段