2009年3月20日星期五

twisted的异步程序

并发程序介绍

许多计算任务的完成需要相当多的时间,为什么一个任务需要相当多的时间有两个原因:

1.它是高强度的运算(例如因子分解大量的数目),需要一定的CPU时间来计算答案;

2.它不是一个高强度的运算,但是不得不为产生一个结果等待可用的数据。

等待回答

网络程序一个基本的功能是等待数据。想象你有个发送一个概述一些信息的email的函数,这个函数需要连接到一个远程服务器,等待远程服务器的回复,检查远程服务器可否处理该email,等待回复,发送email,等待确认,然后断开连接。

这些步骤中的任一个都可能需要很长一段时间。你的程序可以使用所有可能的模型中最简单的,在这种情况下,它实际上坐下并等待数据被发送和接受,但是这种情况中,它有一些明显和根本的局限性:它不能立刻发送多个邮件;并且事实上当它正发送邮件时,不能做其他的任何事情。

因此,除了最近简单的网络程序外所有的网络程序都避免这种模式。你可以用多中不同模式中的一个,来保持你的程序一直工作,当它正等待一个特定的任务之前发生的一些事情时,任何手边现有的任务都可以继续。

不等待数据

编写网络程序有多种方式。主要的是:

1.用一个分离的操作系统进程处理每个连接,在这种情况中,当一个进程在等待时,操作系统将小心的让其他进程运行;

2.用一个分离的线程处理每个连接,在这种情况中,当一个线程在等待时,线程框架小心的让其他线程运行;

3.在一个线程中使用非阻塞系统调用处理所有的连接。

非阻塞调用

当使用Twisted框架时通常的模块是第三个模块:非阻塞调用。

当在一个线程中处理多个连接时,调度是应用程序的职责,而不是操作系统的职责,并且当每个连接准备读取或写入时通过调用一个注册的函数来实现--通常知名的是asynchronous,event-driven和callback-based程序。

在这种模型中,早期的email发送函数这样工作:

1.它调用一个连接函数连接远程的服务器;

2.该连接函数立即返回,当该连接被建立时,隐含的通知该email发送程序将被调用;

3.并且一旦连接被建立,连接机制将通知该email发送函数,连接已经就绪。

上面的顺序覆盖我们原始的阻塞序列有什么好处?好处是当该email发送函数直到连接被打开时不能完成它的工作的下一部分时,程序的其余部分可以完成其他任务,例如为其他email连接开始打开序列。因此,整个程序不再等待连接。

回调

典型的异步模块警告一些数据已经就绪就是知名的回调。应用调用一个函数请求一些数据,并且在这个调用中,它也传递一个当数据已经就绪时调用的回调函数作为一个参数。因此该回调函数应该执行该应用需求的数据的任何任务。

在同步程序中,一个函数请求数据,等待数据,然后处理它,在异步程序中,一个函数请求数据,当数据就绪时让库调用回调函数。

延迟

Twisted使用Deferred对象管理回调序列。当异步请求可用时,客户端附加一系列数据给调用的延迟(deferred)(这一些函数就是一系列callbacks,或一个callback chain),在异步请求中如果有一个错误也附加一系列被调用的函数(errbacks和一个errback chain)。当结果可用时,异步库代码调用第一个回调,或者当一个错误发生时调用第一个errback,并且然后Deferred对象管理每个callback或errback函数的结果给链中的下一个函数。

延迟解决的问题

并发问题的第二种--非高强度计算任务涉及一个可见的延迟--Deferreds被设计用来解决这个问题。等待硬件访问,数据库访问,和网络访问函数都包含在这种情况中,多用时间延迟改变。

Deferreds被设计用来使Twisted程序等待数据时数据到达前而不用被挂起。它实现这个通过为调用的(程序)库和调用的应用给出一个简单的管理接口。库理解通过调用Deferred.callback

没有评论:

发表评论