高性能差异比较工具

一个结合Python和Rust的高性能字符串差异比较工具,适用于需要快速处理大量文本差异的场景。

  • by Krumbthi
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 Krumbthi/fast-diff-mcp

使用说明

以下指南由kweinmeister在medium上编写。这是他的回购https://github.com/kweinmeister/fast-diff-mcp/tree/main

Python和Rust互操作性:构建高性能MCP服务器的演练

2025年10月20日

多年来,我们被告知要站在一边。你在Python团队吗?在那里你可以以闪电般的速度构建复杂的应用程序?或者你在Rust团队,在那里你可以用一种连续9年最受尊敬的语言获得精英性能和内存安全?

现在,得益于PyO3等库,实现了两全其美。PyO3提供了一组Rust宏,用于处理Python和Rust数据类型之间转换的低级细节。

在本指南中,您将逐步学习如何将Rust代码包含在Python代码中。我们将为符合模型上下文协议的AI代理构建一个工具。我们将用Rust编写计算密集型部分,并将其封装在友好的Python接口中。

我们的用例将是一个字符串差异工具。区分文本是适合Rust的CPU繁重任务的一个完美例子。然后,我们将使用Python内置的difflib对我们的创建进行测试,以衡量性能的提高。

本指南中的所有代码都可以在快速diff-mcp GitHub存储库中找到。事实上,您可以按照README中的步骤直接在Gemini CLI或您最喜欢的开发工具中运行MCP服务器。

项目设置和工作流程

在开始之前,请确保您拥有Rust工具链、Python 3.10或更高版本以及基于Rust的Python包管理器uv。

初始化Python Rust项目

为了弥合Rust代码和Python世界之间的差距,我们需要一个专门的构建工具。Maturin编译了我们的Rust代码,并将其打包为可以导入的标准Python轮。

让我们使用PyO3绑定创建一个名为fast-diff-mcp的新项目,并切换到该目录:

uvx maturin new -b pyo3 fast-diff-mcp
cd fast-diff-mcp

由于fastmcp至少需要Python 3.10,如果需要,请在pyproject.toml文件中更新项目中Python的最低版本:

[project]
name = "fast-diff-mcp"
requires-python = ">=3.10"

设置虚拟环境

接下来,让我们用uv创建一个Python虚拟环境。这可以防止我们项目的依赖关系与其他项目发生冲突。

uv venv
source .venv/bin/activate

添加依赖关系

我们的项目需要两种语言的依赖关系。

对于Python,我们将使用uv add。我们的MCP服务器需要fastmcp。对于我们的开发设置,我们将添加pyo3-stubgen来生成打字存根,faker和pyperf用于基准测试,maturin来记录它在项目中的使用。我们还将在“可编辑”模式下添加自己的项目,以便立即获取更改。

# Add the application framework
uv add fastmcp

# Add development tools to the 'dev' extra group
uv add --optional dev pyo3-stubgen faker pyperf maturin
uv add --optional dev --editable .

对于Rust,我们将使用cargo add。我们需要类似的高性能diffing和pyo3用于Python绑定。

cargo add similar
cargo add pyo3 --features "extension-module"

最后,使用一个命令安装Python依赖项:

uv pip install ".[dev]"

编写Rust逻辑

是时候在src/lib.rs中编写应用程序逻辑了。Rust docstring(///)自动成为Python工具的docstring。pyo3中的[#[pyfunction]和#[pymodule]宏完成了将Rust函数暴露给Python的所有繁重工作。您可以使用以下代码更新src/lib.rs中的模板代码:

// src/lib.rs
use pyo3::prelude::*;
use similar::TextDiff;

/// Compares two multiline strings and returns the difference in the
/// standard unified diff format. This is a high-performance implementation
/// written in Rust.
#[pyfunction]
fn unified_diff(text1: String, text2: String) -> PyResult<String> {
    let diff = TextDiff::from_lines(&text1, &text2);
    let diff_output = diff.unified_diff().header("original", "modified").to_string();
    Ok(diff_output)
}

#[pymodule]
fn fast_diff_mcp(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(unified_diff, m)?)?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let result = unified_diff("a\nb\n".to_string(), "a\nc\n".to_string()).unwrap();
        assert_eq!(result, "--- original\n+++ modified\n@@ -1,2 +1,2 @@\n a\n-b\n+c\n");
    }
}

在继续之前,使用maturin构建模块,开发并运行cargo测试:

maturin develop
cargo test

cargo test 验证您的代码是否正常工作。如果你在你的环境中看到链接器错误,你可以设置-L标志来查找你的Python库目录,设置-L来查找Python版本。有关更多信息,请参阅货物文件。

RUSTFLAGS="-L $(python -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))") -lpython$(python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')")" cargo test

生成Python存根

Python的很大一部分吸引力在于强大的编辑器支持。我们不想失去它。通过生成一个.pyi存根文件,我们可以为编辑器提供编译后的Rust代码的映射,从而启用自动补全和类型检查:

pyo3-stubgen fast_diff_mcp .

开发过程

我们现在已经走过了主要步骤。让我们回顾一下如何随着代码的发展进行迭代。您可以在src/lib.rs中编辑Rust代码,用cargo test验证您的逻辑,然后运行maturin develop执行增量重建,以可编辑模式安装模块。如果更改了任何函数签名,请重新运行pyo3 stubgen fast_diff_mcp。保持编辑器的自动补全功能同步。

与Python集成

编译完Rust二进制文件后,我们可以将新模块导入Python应用程序。我们的server.py将定义两个工具:一个使用我们新的Rust函数,一个使用Python的标准difflib,这样我们就可以比较它们了。

import asyncio
import logging
import os
from typing import List, Iterator

from fast_diff_mcp import unified_diff
from fastmcp import FastMCP
import difflib

logger: logging.Logger = logging.getLogger(__name__)
mcp: FastMCP = FastMCP("fast-diff-mcp")


@mcp.tool()
def diff_tool_rust_similar(original_text: str, modified_text: str) -> str:
    """
    Compares two multiline strings and returns the difference in the
    standard unified diff format. This is a high-performance implementation
    written in Rust, using the `similar` crate's Myers diff algorithm.
    """
    logger.info(">>> Tool: 'diff_tool_rust_similar' called")
    return unified_diff(original_text, modified_text)


@mcp.tool()
def diff_tool_python_difflib(original_text: str, modified_text: str) -> str:
    """
    Compares two multiline strings using the standard Python `difflib`
    library, which uses the Ratcliff/Obershelp algorithm.
    """
    logger.info(">>> Tool: 'diff_tool_python_difflib' called")
    original_lines: List[str] = original_text.splitlines(keepends=True)
    modified_lines: List[str] = modified_text.splitlines(keepends=True)
    diff: Iterator[str] = difflib.unified_diff(
        original_lines, modified_lines, "original", "modified"
    )
    return "".join(diff)


if __name__ == "__main__":
    logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)
    logger.info(f" MCP server started on port {os.getenv('PORT', 8080)}")
    asyncio.run(
        mcp.run_async(
            transport="streamable-http",
            host="0.0.0.0",
            port=int(os.getenv("PORT", 8080)),
        )
    )

现在,您可以安装您的项目,包括pyproject.toml中指定的Rust依赖项:

uv pip install -e .
uv run server.py

fastmcp命令行界面包含一个dev命令,该命令与MCP Inspector一起启动服务器,MCP Inspecter是一个用于测试服务器工具的图形用户界面。

要尝试它,请运行以下命令。这将启动您的服务器,并在新的浏览器窗口中打开检查器。

uv run fastmcp dev server.py 检查器应自动连接到您的服务器。如果没有,请选择传输,然后单击连接按钮。接下来,单击顶部的“工具”选项卡。单击“列出工具”按钮。您应该看到diff_tool_rust_similar出现在左侧的列表中。

单击diff_tool_rust_similar。右侧将出现一个表单,其中包含original_text和modified_text字段。在输入框中输入文本。例如:

原始文本:

第1行 line2_old 第3行 修改文本:

第1行 line2_new 第3行 单击运行工具按钮。该工具的输出将出现在表单下方的“结果”部分,显示统一的差异。

按enter键或单击查看全尺寸图像

基准测试:Rust与Python

那么,它快了多少?我们可以使用pyperf库来查找。我们的benchmark.py脚本将基于Rust的unified_diff与Python的difflib进行了比较。我在MacBook Pro上本地运行的基准测试表明,Rust实现的速度是它的两倍多。

按enter键或单击查看全尺寸图像

对于这个基准测试,有一些重要的细节需要记住。首先,这包括整个MCP call_tool函数范围,其中包括初始化代码和协议开销。仅对diff算法函数进行基准测试将导致更大的差异。

我使用了1000万个字符的大字符串来模拟日志处理用例。较小的字符串会缩小差距,而较大的字符串会由于固定的协议开销而增加差距。

最后,Rust的diff实现使用Myers算法,而Python算法使用Ratcliff/Obershelp。在最初的基准测试中,我还尝试了myers Python库。对于较小的字符串,它的性能优于内置的Python difflib实现,但对于较大的字符串,其扩展性不佳。

Python diff实现和基准代码位于GitHub存储库中。自己试试这个基准!

uv run python benchmark.py

结论

你不再被迫在Python的开发速度和Rust的执行速度之间做出选择。你可以两者兼得。Rust不是Python的替代品,而是一个强大的盟友。找到你的瓶颈,将它们卸载到Rust,并改进你的应用程序。

要了解更多关于在云中使用Rust的信息,请查看Google Cloud的官方Rust SDK。有关构建纯Rust MCP服务器的示例,请参阅构建可扩展的AI代理。