杰瑞科技汇

Python如何编译libevent?

理解 libevent 的编译过程对于理解底层依赖非常有帮助。libevent 本身是一个用 C 语言编写的库,因此编译它需要 C 语言编译环境。

Python如何编译libevent?-图1
(图片来源网络,侵删)

我将分两种情况来解释:

  1. 编译 libevent C 库本身 (通常是作为其他 Python 依赖的编译步骤)
  2. 在 Python 中使用 libevent (这是更常见的需求)

从源码编译 libevent C 库

如果你需要从 .tar.gz 源码包编译 libevent,通常是因为某个 Python 包(比如旧版的 gevent)需要它作为依赖,并且你无法通过系统包管理器或 pip 获取预编译版本。

准备工作

你需要一个 C 语言编译环境。

  • 在 Linux (Ubuntu/Debian) 上:

    sudo apt-get update
    sudo apt-get install build-essential

    build-essential 包含了 gcc, make, autoconf 等基本编译工具。

  • 在 macOS 上: 使用 Homebrew 安装 Xcode Command Line Tools:

    xcode-select --install

    或者通过 Homebrew 安装:

    brew install autoconf automake libtool

编译步骤

假设你已经下载了 libevent 的源码压缩包(libevent-2.1.12-stable.tar.gz)并解压。

  1. 进入源码目录

    cd libevent-2.1.12-stable
  2. 配置编译选项 运行 ./configure 脚本来检查你的系统环境并生成 Makefile,你可以添加一些有用的选项:

    • --prefix=/usr/local: 指定安装路径,这是推荐的做法,可以避免和系统自带的库冲突。
    • --disable-shared: 只编译静态库 (.a 文件),对于作为依赖库来说,静态库通常更简单,因为不需要处理运行时的库路径问题。
    • --enable-static: 与 --disable-shared 效果类似,显式地启用静态库。

    一个推荐的配置命令:

    ./configure --prefix=/usr/local --disable-shared

    如果一切顺利,你会看到一堆 checking for ... 的输出,最后提示 configure finished

  3. 编译 运行 make 来编译源代码。-j 选项可以指定并行编译的线程数,加快编译速度(通常使用你的 CPU 核心数)。

    make -j$(nproc)  # Linux
    # 或者
    make -j$(sysctl -n hw.ncpu) # macOS
    # 或者直接
    make
  4. 安装 运行 make install 将编译好的库文件和头文件安装到你指定的目录(这里是 /usr/local)。

    sudo make install

    安装后,libevent 的头文件会放在 /usr/local/include,库文件会放在 /usr/local/lib

系统已经可以找到 libevent 了,如果你需要编译一个依赖它的 Python 包,它的 setup.py 脚本通常能自动在 /usr/local 等标准路径下找到它。


在 Python 中使用 libevent (更常见的需求)

对于 Python 你几乎不需要手动编译 libevent C 库,你的目标是安装一个 Python 封装器,这个封装器会自动处理 C 库的依赖。

这里主要有两种选择:

选择 A: 使用 gevent (推荐)

gevent 是一个基于 libeventlibuv 的高性能网络库,它通过协程(cooperative multitasking)实现了异步 I/O,是 Python 中 libevent 思想最流行的实现。

优点:

  • API 友好: 提供了与标准库 threadingsocket 非常相似的 API,学习成本低。
  • 功能强大: 广泛应用于高并发网络服务,如 Web 服务器、爬虫等。
  • 自动依赖: 当你用 pip 安装 gevent 时,它会尝试自动找到或编译 libevent,你通常不需要关心 libevent 的存在。

安装和使用:

  1. 安装 gevent

    pip install gevent
  2. 简单示例代码 gevent 会自动将标准的阻塞 I/O 操作(如 socket.connect, requests.get)切换到非阻塞模式。

    import gevent
    from gevent import socket
    import time
    def fetch(host):
        start = time.time()
        try:
            # gevent 会自动将这个阻塞的 socket 操作变成非阻塞的
            s = socket.create_connection((host, 80))
            s.sendall(b"GET / HTTP/1.1\r\nHost: " + host.encode() + b"\r\nConnection: close\r\n\r\n")
            data = s.recv(1024)
            print(f"Successfully fetched {host} in {time.time() - start:.2f} seconds.")
        except Exception as e:
            print(f"Failed to fetch {host}: {e}")
    # 创建多个 "greenlet" (类似轻量级线程)
    jobs = [gevent.spawn(fetch, "www.google.com"), gevent.spawn(fetch, "www.github.com")]
    # 等待所有 greenlet 完成
    gevent.joinall(jobs)
    print("All tasks done.")

    运行这段代码,你会发现两个网络请求几乎是同时发起的,而不是一个接一个地等待,这就是 gevent 的威力。

选择 B: 使用 pylibevent

pylibevent 是一个更直接的 libevent 的 Python 绑定,它暴露了 libevent 的底层 API。

优点:

  • 底层控制: 提供了对 libevent 事件循环、事件类型等的直接访问。
  • 轻量级: 如果你对 gevent 的协程模型不感兴趣,只想用事件循环,这是一个选择。

缺点:

  • API 复杂: 需要理解 libevent 的工作方式,event_base, event, bufferevent 等概念,学习曲线较陡峭。
  • 社区较小: 不如 gevent 流行,社区支持和资源较少。

安装和使用:

  1. 安装 pylibevent

    pip install pylibevent

    这个安装过程可能会失败,如果系统缺少 libevent 的开发包(libevent-devlibevent-devel),这时你可能需要先安装它:

    • Ubuntu/Debian: sudo apt-get install libevent-dev
    • CentOS/RHEL: sudo yum install libevent-devel
    • macOS (with Homebrew): brew install libevent
  2. 简单示例代码 这个例子会监听标准输入,当有数据可读时打印出来。

    import pylibevent
    import sys
    # 创建一个事件基础
    base = pylibevent.event_base_new()
    # 定义一个回调函数
    def on_stdin_read(fd, event, arg):
        print("Data is available on stdin!")
        data = sys.stdin.readline()
        print(f"You entered: {data.strip()}")
        # 注意:这里只是简单示例,实际应用中你可能需要处理更复杂的逻辑
        # 并且可能需要停止事件循环
        # pylibevent.event_del(event)
    # 获取标准输入的文件描述符
    stdin_fd = sys.stdin.fileno()
    # 创建一个事件
    # 参数:文件描述符, 事件类型 (EV_READ | EV_PERSIST), 回调函数, 回调参数
    event = pylibevent.event_new(base, stdin_fd, pylibevent.EV_READ | pylibevent.EV_PERSIST, on_stdin_read, None)
    # 添加事件到事件基础
    pylibevent.event_add(event, None) # None 表示没有超时
    print("Waiting for input... Press Ctrl+C to exit.")
    # 进入事件循环
    pylibevent.event_base_dispatch(base)
    # 清理
    pylibevent.event_del(event)
    pylibevent.event_free(event)
    pylibevent.event_base_free(base)

总结与建议

特性 编译 libevent C 库 使用 gevent 使用 pylibevent
目标用户 系统管理员、C/C++ 开发者、Python 包维护者 Python 开发者 (推荐) 对底层事件循环有特殊需求的 Python 开发者
操作 手动 ./configure, make, make install pip install gevent pip install pylibevent
复杂度
主要用途 作为其他软件的依赖 构建异步、高并发的 Python 应用 精细控制 libevent 事件循环

给你的最终建议:

99% 的 Python 开发者都应该选择 gevent 它为你处理了所有底层复杂性,并提供了一个强大、易用且成熟的异步编程框架,你不需要关心 libevent 是如何被编译和安装的,只需要专注于你的业务逻辑即可。

只有在你的项目有特殊需求,明确需要绕过 gevent 的协程层,直接操作 libevent 的事件循环时,才应该考虑 pylibevent

分享:
扫描分享到社交APP
上一篇
下一篇