eventlet implementation explained 1

本文介绍Eventlet,一种基于greenlet的异步I/O库,通过一个echo服务器示例展示了其非阻塞特性及内部实现机制,包括如何处理连接、读写操作以及事件监听。

Eventlet is an asynchronouse I/O library which is based on greenlet. We can write very efficient network programms with eventlet without using threads. So let’s see how it is implemented. We start from an echo server example which you can find in eventlet.

#! /usr/bin/env python
"""/
Simple server that listens on port 6000 and echos back every input to
the client.  To try out the server, start it up by running this file.

Connect to it with:
  telnet localhost 6000

You terminate your connection by terminating telnet (typically Ctrl-]
and then 'quit')
"""

import eventlet

def handle(fd):
    print "client connected"
    while True:
        # pass through every non-eof line
        x = fd.readline()
        if not x: break
        fd.write(x)
        fd.flush()
        print "echoed", x,
    print "client disconnected"

print "server socket listening on port 6000"
server = eventlet.listen(('0.0.0.0', 6000))
pool = eventlet.GreenPool()
while True:
    try:
        new_sock, address = server.accept()
        pool.spawn_n(handle, new_sock.makefile('rw'))
    except (SystemExit, KeyboardInterrupt):
        break

At first look, everything seems to be blocking. But note that no standard library is explicitly imported, the socket we use is provided by eventlet, which is non-blocking by default.

We need to launch a debugger (I use spe with winpdb) to see what really happens insided eventlet. Let me present you the stack trace.

socket.accept
    socket_accept(fd)
        py.socket.accept # standard api is called
            return None for non-blocking if no incoming connection
            return Not None if has incoming connection
        trampoline # if no incomming connection
            hub.add # add a FdListener
                add the listener to the queue correponding the fd(socket)
                callback of the listener is greenlet.current.switch which is the main thread
            hub.switch
                hub.greenlet.switch # run = hub.run (hub -> BaseHub
                    BaseHub.run # main loop, this is a greenlet
                        prepare_timers # sort timers
                        fire_timers    # fire timers with current tick
                        prepare_timers # why ???
                        wait # wait a period of timer
                            py.select.select # wait
                            if has avail readers
                                FdListeners[0](fd) # notify the listerner, read/write can be performed without blocking,
                                                   # callback is to switch to trampoline
            hub.remove # remove a listener, we reach here if there're some read/write events

If there’s no incoming connection, trampoline is called. This function is very important to eventlet, such as accept, recv, readline will call this function inside. Within trampoline, a listener is added to a the hub which is the core of eventlet. When there’s any read/write events, corresponding listeners will be called, so that we can at on the events. The callback of listeners are greenlet which by default are the main greenlet. In this example, if there’s a client connecting to the server, a listerner is notified. Remember that the callback of a listener is a greenlet, which is by default the main greenlet, this means that we will switch back to trampoline, and then return to our main loop to spawn a new handler.

Now we are spawning a handler, below is the stack trace of spawn_n.

GreenPool.spawn_n
    greenthread.spawn_n
        _spawn_n # create a greenlet of the client handler
        hub.schedule_call_global # create a corresponding timer, and then add the timer to a list which is a priority queue.

GreenPool.spawn_n just creates a timer which will be process when accept is called in the next loop run. The timer contains a greenlet which wraps our handle function.

In next loop, server.accept is called again. Assume that there’s no new incoming connection, trampoline is called and we will switch to the main loop. Timers will be processed, our handle function is called. If there’s no recving data, we then switching to the main loop.

It’s a bit complex, since the control flow is not linear. After you have a basic grasp of what’s going on, you will be fine.

### 关于 PDF 的定义及其工作原理 PDF 是 Portable Document Format(便携式文档格式)的缩写,由 Adobe 开发并于 1993 年首次发布。它是一种通用文件格式,旨在捕获来自任何应用程序的字体、图像、超链接和其他多媒体内容,并将其封装到一个独立且可移植的文档中[^5]。 #### 特性和功能 PDF 文件的主要特性之一是其跨平台兼容性。无论是在 Windows、MacOS 还是 Linux 上打开,PDF 文档都能保持原始布局和样式不变。这种一致性得益于 PDF 使用的一种固定版面技术,该技术基于 PostScript 页面描述语言并扩展了其功能[^6]。 #### 工作机制 PDF 的内部结构可以分为以下几个部分: 1. **对象模型**:PDF 中的内容被表示为一系列的对象,这些对象包括字典、数组、字符串以及流数据等基本单元。 2. **交叉引用表**:为了快速定位特定对象的位置,在文件末尾通常会有一个交叉引用表记录各个对象在文件中的偏移量。 3. **压缩方法**:许多现代 PDF 实现都采用了 Flate 解码或其他更先进的算法来减小文件大小而不损失质量[^7]。 当创建一个新的 PDF 或者编辑现有 PDF 时,软件程序按照上述标准构建相应的对象树并将它们序列化成二进制形式存储起来;而读取 PDF 则相反——解析器先加载整个文件进入内存缓冲区,接着通过查找根目录找到页面集合及其他资源位置,最后渲染显示给用户查看。 此外值得注意的是随着互联网的发展和技术进步,如今除了静态文本图片外还支持嵌入音频视频甚至交互控件等功能丰富的动态型 PDF 应用场景也越来越多见比如电子书在线表单签名验证等等[^8]。 ```python from PyPDF2 import PdfReader reader = PdfReader("example.pdf") number_of_pages = len(reader.pages) page = reader.pages[0] text = page.extract_text() print(text) ``` 以上是一个简单的 Python 脚本例子展示如何利用第三方库 `PyPDF2` 提取 PDF 第一页上的纯文字信息作为演示用途仅限于此实际应用可能涉及更多复杂操作像加密解密旋转裁剪合并拆分转换导出等多种需求均可满足取决于具体开发环境和个人偏好选用合适工具完成相应任务即可[^9]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值