Elasticsearch Python 客户端是否与自由线程 Python 兼容?

作者:来自 Elastic Quentin_Pradet

在这篇文章中,我们将进行一些实验,看看 Python Elasticsearch 客户端是否与新的 Python 3.13 自由线程(free-threading)版本兼容,其中 GIL 已被删除。

介绍

但首先,什么是 GIL?全局解释器锁 (Global Interpreter Lock - GIL) 是一个保护对 Python 对象访问的互斥锁,可防止多个线程同时执行 Python 字节码。在实践中这并不总是一个问题。

  • 科学编程可以使用不包含 GIL 的库(如 NumPy)。
  • 有些程序不是 CPU 密集型的,而是 I/O 密集型的。例如,如果你的代码向 Elasticsearch 发出昂贵的请求,但不会对结果进行昂贵的计算,则它可以有效地使用多个线程。事实上,即使只有一个线程正在执行,它也不会阻塞等待 I/O 的其他线程,从而不会阻塞 GIL。 (这也是 async/await 在 Python 中大放异彩的场景。)

然而,几十年来,人们的目标一直是消除这一限制并实现真正的多线程编程。感谢 Sam Gross 的出色工作,现在这一切成为了可能!这项工作最初被称为 nog​​il,但现在被称为 free-threading。虽然现有的纯 Python 代码与生成的构建仍然以相同的方式工作(尽管目前单线程代码速度较慢),但从 C 或 Rust 等其他语言编译的所有代码都需要重构。在过去,这种向后不兼容的变化足以成为发布 Python 4 的理由。然而,Python 3 迁移导致了超过 10 年的语言分裂,由此造成的痛苦仍然历历在目。因此,目前的计划是逐步推出:

  • 作为第 1 阶段(当前阶段)的一部分,Python 3.13 提供了实验性的自由线程版本,每个库和应用程序都需要测试它们的兼容性。
  • 在第二阶段,这些构建将不再被称为 “实验性的”。
  • 在第 3 阶段,标准 Python 构建将包括自由线程支持。

Elasticsearch Python 客户端是纯 Python 代码,不涉及太多线程或特定依赖垃圾收集器,因此它应该可以与自由线程构建一样好地运行。但是,它确实具有受影响的可选依赖项,例如 aiohttp 或 orjson。

我们将测试这些不同的部件,看看它们是否正常工作。基准测试将作为练习留给读者!

使用自由线程 Python

有多种方法可以安装自由线程的 Python 版本。我们将使用 Astral 的 uv 包管理器,它允许使用 --python 3.13t 指定自由线程构建。 Astral 为 python-build-standalone 贡献了自由线程构建,如果需要,uv 将会使用它们:

$ uv run --python 3.13t python
Using CPython 3.13.0
Creating virtual environment at: .venv
Installed 4 packages in 16ms
Python 3.13.0 experimental free-threading build (main, Oct 16 2024, 08:24:33)
[Clang 18.1.8 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

但是,如果你已经安装了自由线程解释器,uv 将使用它而不是 python-build-standalone。例如,如果你想在 macOS 上使用 Homebrew 提供的构建(使用 brew install python-freethreading 安装),你将得到以下输出:

$ uv run --python 3.13t python
Using CPython 3.13.0 interpreter at:
/opt/homebrew/opt/python-freethreading/bin/python3.13t
Creating virtual environment at: .venv
Installed 4 packages in 4ms
Python 3.13.0 experimental free-threading build (main, Oct  7 2024, 05:02:14)
[Clang 16.0.0 (clang-1600.0.26.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

由于 uv 还支持内联脚本元数据标准,我们将提供如下独立的代码片段:

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "numpy",
# ]
# ///
import numpy as np

c = np.arange(24).reshape(2, 3, 4)

你可以运行它们,而不必担心虚拟环境或手动安装依赖项:

$ uv run --python 3.13t example.py
Reading inline script metadata from `example.py`
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

使用 Elasticsearch

得益于 start-local 脚本,Elasticsearch 同样易于运行:

$ curl -fsSL https://elastic.co/start-local | sh

  ______ _           _   _
 |  ____| |         | | (_)
 | |__  | | __ _ ___| |_ _  ___
 |  __| | |/ _` / __| __| |/ __|
 | |____| | (_| \__ \ |_| | (__
 |______|_|\__,_|___/\__|_|\___|
-------------------------------------------------
🚀 Run Elasticsearch and Kibana for local testing
-------------------------------------------------

ℹ️  Do not use this script in a production environment

⌛️ Setting up Elasticsearch and Kibana v8.16.0...

- Generated random passwords
- Created the elastic-start-local folder containing the files:
  - .env, with settings
  - docker-compose.yml, for Docker services
  - start/stop/uninstall commands
- Running docker compose up --wait

🎉 Congrats, Elasticsearch and Kibana are installed and running in Docker!

🌐 Open your browser at http://localhost:5601
🔌 Elasticsearch API endpoint: http://localhost:9200

我们来测试一下:

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "elasticsearch",
# ]
# ///
import os
import sys

from elasticsearch import Elasticsearch

print(sys.version)
client = Elasticsearch(
    "http://localhost:9200", api_key=os.environ["ES_LOCAL_API_KEY"]
)
print(client.info()["tagline"])

虽然 start-local 不使用 HTTPS,但它确实设置了身份验证。相关机密存储在 elastic-start-local/.env 文件中,因此我们可以获取它并将 ES_LOCAL_API_KEY 作为环境变量传递:

$ source elastic-start-local/.env
$ ES_LOCAL_API_KEY=$ES_LOCAL_API_KEY uv run --python 3.13t ex1.py
Reading inline script metadata from `ex1.py`
3.13.0 experimental free-threading build (main, Oct 16 2024, 08:24:33)
[Clang 18.1.8 ]
You Know, for Search

太棒了!一个简单的查询就按预期工作了。现在,让我们测试 Python 客户端的其他区域。

批量助手 - bulk helper

我们在 Python 客户端中明确使用线程的唯一地方是在 parallel_bulk 帮助程序中。让我们索引 books.csv 数据集并进行查询以查看是否有效。

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "elasticsearch",
# ]
# ///
import csv
import os
import sys
import time

from elasticsearch import Elasticsearch, helpers

client = Elasticsearch(
    "http://localhost:9200", api_key=os.environ["ES_LOCAL_API_KEY"]
)

mappings = {
    "properties": {
        "Title": {"type": "text"},
        "Description": {"type": "text"},
        "Author": {"type": "text"},
        "Year": {"type": "date", "format": "yyyy"},
        "Published": {"type": "keyword"},
        "Rating": {"type": "scaled_float", "scaling_factor": 100},
    }
}

client.options(ignore_status=[404]).indices.delete(index="books")
client.indices.create(index="books", mappings=mappings)
print("Created index")


def generate_docs():
    with open("books.csv", newline="") as csvfile:
        reader = csv.DictReader(csvfile, delimiter=";")
        for row in reader:
            yield {"_index": "books", **row}


start = time.perf_counter()
n, errors = helpers.bulk(client, generate_docs())
end = time.perf_counter()
print(f"Indexed {n} books in {end - start:.1f} seconds.")

client.indices.refresh(index="books")

print("Searching for Stephen King:")
resp = client.search(
    index="books", query={"match": {"Author": "Stephen King"}}
)
for hit in resp.body["hits"]["hits"]:
    book = hit["_source"]
    description = f'{book["Author"]} - {book["Title"]} ({book["Year"]})'
    rating = f'{book["Ratings"]} stars'
    print(f"  {description}: {rating}")

脚本的输出显示我们确实在不到 2 秒的时间内索引了所有 82k 本书!这比标准批量助手快大约 2 倍

$ ES_LOCAL_API_KEY=$ES_LOCAL_API_KEY uv run --python 3.13t ex2.py
Reading inline script metadata from `ex2.py`
Created index
Indexed 81828 books in 1.6 seconds.
Searching for Stephen King:
  Stephen King - THE ELEMENTS OF STYLE (2013): 5.00 stars
  Stephen King - Star (Thorndike Core) (2021): 3.11 stars
  Stephen King - Hearts in Atlantis (2017): 4.08 stars
  Stephen King - Misery (Spanish Edition) (2016): 4.43 stars
  Stephen King - The Dead Zone (2016): 4.40 stars
  Stephen King - Another World (Thorndike Core) (2021): 3.78 stars
  Stephen King - FROM A BUICK 8 (True first edition) (2017): 3.25 stars
  Stephen King - Road Work (2017): 4.29 stars
  Stephen King - Icon (Thorndike Core) (2021): 4.00 stars
  Stephen King - Misery (2016): 4.43 stars

aiohttp

Elasticsearch 的 Python 客户端通过两个 HTTP 客户端(aiohttphttpx)支持 asyncio,默认使用 aiohttp。虽然 aiohttp 尚未正式支持自由线程构建(目前确实无法编译),但可以通过设置 AIOHTTP_NO_EXTENSIONS=1 在纯 Python 模式下使用它。虽然性能会较慢,但可以与自由线程构建兼容。

关于测试,没有太多需要测试的内容,因为 asyncio 事件循环已经局限于单个线程。接下来,让我们复用之前的示例,但改用 asyncio:

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "elasticsearch[async]",
# ]
# ///
import asyncio
import os
import sys

from elasticsearch import AsyncElasticsearch

print(sys.version)


async def main():
    async with AsyncElasticsearch(
        "http://localhost:9200", api_key=os.environ["ES_LOCAL_API_KEY"]
    ) as client:
        info = await client.info()
        print(info["tagline"])


asyncio.run(main())

由于 uv run 会动态安装依赖项,因此我们需要定义 AIOHTTP_NO_EXTENSIONS 来运行。事实上,脚本的行为符合预期:

$ export AIOHTTP_NO_EXTENSIONS=1
$ export ES_LOCAL_API_KEY=$ES_LOCAL_API_KEY
$ uv run --python 3.13t ex3.py
Reading inline script metadata from `ex3.py`
3.13.0 experimental free-threading build (main, Oct 16 2024, 08:24:33
[Clang 18.1.8 ]
You Know, for Search

序列化和反序列化

Elasticsearch Python 客户端支持多个库来序列化或反序列化数据。出于性能原因,他们经常使用本机代码,并且这些库需要进行调整才能与自由线程构建配合使用。

orjson 允许快速序列化/反序列化 JSON,但尚不支持自由线程构建,甚至无法编译。

PyArrow 18+ 和 Pandas 2.2.3+ 支持自由线程构建。让我们通过进行 ES|QL 查询来重用书籍索引:

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "elasticsearch",
#     "pandas",
#     "pyarrow",
# ]
# ///
import csv
import os
import sys
import time

import pandas as pd
from elasticsearch import Elasticsearch, helpers

client = Elasticsearch(
    "http://localhost:9200", api_key=os.environ["ES_LOCAL_API_KEY"]
)

print("Searching for Stephen King:")
resp = client.esql.query(
    query="""
    FROM books
    | WHERE Author == "Stephen King"
    | SORT Rating DESC
    | LIMIT 10
    """,
    format="arrow",
)
df = resp.to_pandas(types_mapper=pd.ArrowDtype)
print(df)

输出以下内容:

$ PYTHON_GIL=0 ES_LOCAL_API_KEY=$ES_LOCAL_API_KEY uv run --python 3.13t ex4.py
Reading inline script metadata from `ex4.py`
Searching for Stephen King:
         Author  ...                                Title                 Year
0  Stephen King  ...       Another World (Thorndike Core)  2021-01-01 00:00:00
1  Stephen King  ...  FROM A BUICK 8 (True first edition)  2017-01-01 00:00:00
2  Stephen King  ...                   Hearts in Atlantis  2017-01-01 00:00:00
3  Stephen King  ...             Misery (Spanish Edition)  2016-01-01 00:00:00
4  Stephen King  ...       The Dark Tower: The Gunslinger  2017-01-01 00:00:00
5  Stephen King  ...                        The Dead Zone  2016-01-01 00:00:00
6  Stephen King  ...           NIGHTMARES AND DREAMSCAPES  2017-01-01 00:00:00
7  Stephen King  ...                    How writers write  2002-01-01 00:00:00
8  Stephen King  ...                THE ELEMENTS OF STYLE  2013-01-01 00:00:00
9  Stephen King  ...                            Road Work  2017-01-01 00:00:00

请注意,我必须设置 PYTHON_GIL=0 来禁用以下警告,我认为不应该发出该警告,因为这些库确实支持自由线程构建。也许这个问题将在未来的版本中得到修复。

结论

总而言之,自由线程构建的效果出奇地好!许多重要的库已经支持自由线程。虽然仍然存在一些不受支持的库,例如 orjson 或 Polars,但它们是例外,而不是规则。自由线程的前景光明,我可以看到这些构建很快就会脱离实验状态。 (但在这种情况发生之前,我建议不要在生产中使用它们。)

如果你想了解有关自由线程的更多信息,https://py-free-threading.github.io/是一个很好的资源,特别是更多资源页面链接到有用的学习材料。

回答我最初的问题:是的,Python Elasticsearch 客户端在自由线程下运行得很好!

原文:Dec 4th, 2024: [EN] Does the Elasticsearch Python client work with free-threading Python? - Advent Calendar - Discuss the Elastic Stack

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/955689.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

当当网书籍信息爬虫

1.基本理论 1.1概念体系 网络爬虫又称网络蜘蛛、网络蚂蚁、网络机器人等,可以按照我们设置的规则自动化爬取网络上的信息,这些规则被称为爬虫算法。是一种自动化程序,用于从互联网上抓取数据。爬虫通过模拟浏览器的行为,访问网页…

【12】Word:张老师学术论文❗

目录 题目 ​NO2 NO3 NO4 NO5 NO6 NO7.8 题目 NO2 布局→页面设置→纸张:A4→页边距:上下左右边距→文档网格:只指定行网格→版式:页眉和页脚:页脚距边界:1.4cm居中设置论文页码:插入…

RabbitMQ实现延迟消息发送——实战篇

在项目中,我们经常需要使用消息队列来实现延迟任务,本篇文章就向各位介绍使用RabbitMQ如何实现延迟消息发送,由于是实战篇,所以不会讲太多理论的知识,还不太理解的可以先看看MQ的延迟消息的一个实现原理再来看这篇文章…

【PCL】Segmentation 模块—— 欧几里得聚类提取(Euclidean Cluster Extraction)

1、简介 PCL 的 Euclidean Cluster Extraction(欧几里得聚类提取) 是一种基于欧几里得距离的点云聚类算法。它的目标是将点云数据分割成多个独立的簇(clusters),每个簇代表一个独立的物体或结构。该算法通过计算点与点…

ElasticSearch上

安装ElasticSearch Lucene:Java语言的搜索引擎类库,易扩展;高性能(基于倒排索引)Elasticsearch基于Lucene,支持分布式,可水平扩展;提供Restful接口,可被任何语言调用Ela…

GitLab:添加SSH密钥之前,您不能通过SSH来拉取或推送项目代码

1、查看服务器是否配置过 [rootkingbal-ecs-7612 ~]# cd .ssh/ [rootkingbal-ecs-7612 .ssh]# ls authorized_keys id_ed25519 id_ed25519.pub id_rsa id_rsa.pub2、创建密钥 $ ssh-keygen -t rsa -C kingbalkingbal.com # -C 后写你的邮箱 一路回车 3、复制密钥 [rootk…

《目标检测数据集下载地址》

一、引言 在计算机视觉的广袤领域中,目标检测宛如一颗璀璨的明星,占据着举足轻重的地位。它宛如赋予计算机一双锐利的 “眼睛”,使其能够精准识别图像或视频中的各类目标,并确定其位置,以边界框的形式清晰呈现。这项技…

Kibana 控制台中提供语义、向量和混合搜索

作者:来自 Elastic Mark_Laney 想要将常规 Elasticsearch 查询与新的 AI 搜索功能结合起来吗?那么,你不需要连接到某个第三方的大型语言模型(LLM)吗?不。你可以使用 Elastic 的 ELSER 模型来改进现有搜索&a…

Golang Gin系列-3:Gin Framework的项目结构

在Gin教程的第3篇,我们将讨论如何设置你的项目。这不仅仅是把文件扔得到处都是,而是要对所有东西的位置做出明智的选择。相信我,这些东西很重要。如果你做得对,你的项目会更容易处理。当你以后不再为了找东西或添加新功能而绞尽脑…

程序设计:排版、检验报告的上下标解决几种办法

【啰嗦两句】 本文重点在于提供几个针对排版文档、各种检验报告系统等程序设计时,遇到的上下标录入、绘制展示等问题的应对办法,但是准确地说,并没有非常优秀的方案。 【上下标难题】 一般的行业或许对上下标并没有严格要求,多数…

TCP 重传演进:TCP RACK Timer 能替代 RTO 吗

本文的建议适用于想改变 TCP 行为的新协议设计,还是那句话,不要抄 TCP 做 yet another TCP。 RTO 一直是 TCP 传输过程所要尽量避免的,因为它会将状态带入 Loss 进而 Go-Back-N,这是一个昂贵的操作。But 在 Fast-Retransmit 被引…

PCL 新增自定义点类型【2025最新版】

目录 一、自定义点类型1、前言2、定义方法3、代码示例二、合并现有类型三、点云按时间渲染1、CloudCompare渲染2、PCL渲染博客长期更新,本文最近更新时间为:2025年1月18日。 一、自定义点类型 1、前言 PCL库自身定义了很多点云类型,但是在使用的时候时如果要使用自己定义的…

Python操作Excel——openpyxl使用笔记(5)

5 其他操作 5.1 合并单元格 有些Excel表格存在合并多个单元格的情况,此时可以使用工作表的merge_cells函数,例如合并第1~2行和1~2列: import openpyxl from openpyxl.comments import Comment wb openpyxl.load_workbook(./test.xlsx) w…

Linux简介和环境搭建

Linux 介绍和环境搭建 1、发行版本 Linux 操作系统有多个主流发行版本,每个版本根据不同的目标、特点和使用场景为用户提供了不同的功能和体验。 Ubuntu • 特点:Ubuntu 是最为人熟知的 Linux 发行版之一,强调易用性和用户友好性&#xff…

LabVIEW时域近场天线测试

随着通信技术的飞速发展,特别是在5G及未来通信技术中,天线性能的测试需求日益增加。对于短脉冲天线和宽带天线的时域特性测试,传统的频域测试方法已无法满足其需求。时域测试方法在这些应用中具有明显优势,可以提供更快速和精准的…

SQL Server查询计划操作符——查询计划相关操作符(4)

7.3. 查询计划相关操作符 28)Declare:该操作符在查询计划中分配一个本地变量。该操作符是一个语言元素。该操作符具体如图7.2-28所示。 图 7.2-28 查询计划操作符Declare示例 29)Delete:该操作符从一个对象中删除满足其参数列中可选谓词的数据行。该操作符具体如图7.2-29…

复用类(3):在组合与继承之间选择、protected关键字、向上转型

1 在组合与继承之间选择 组合和继承都允许在新的类中放置子对象,组合是显式地这样做,而继承则是隐式地做。你或许想知道二者之间的区别何在,以及怎样在二者之间做出选择。 组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。…

Java-数据结构-二叉树习题(1)

对于二叉树的学习,主要的还是得多多练习~毕竟二叉树属于新的知识,并且也并不是线性结构,再加上经常使用递归的方法解决二叉树的问题,所以代码的具体流程还是无法看到的,只能通过画图想象,所以还是必须多加练…

彩色图像面积计算一般方法及MATLAB实现

一、引言 在数字图像处理中,经常需要获取感兴趣区域的面积属性,下面给出图像处理的一般步骤。 1.读入的彩色图像 2.将彩色图像转化为灰度图像 3.灰度图像转化为二值图像 4.区域标记 5.对每个区域的面积进行计算和显示 二、程序代码 %面积计算 cle…

计算机网络 (41)文件传送协议

前言 一、文件传送协议(FTP) 概述: FTP(File Transfer Protocol)是互联网上使用得最广泛的文件传送协议。FTP提供交互式的访问,允许客户指明文件的类型与格式(如指明是否使用ASCII码&#xff0…