Web開発
Pyronaut の紹介
Introducing Pyronaut (pyronaut.io)
要約
Pyronaut は、GraalVM と Micronaut を基盤とした、本番環境対応サービス構築のための高性能 Python アプリケーションプラットフォームです。Python の AST を Java コンパイラと統合し、GraalVM と Graal JIT による実行時最適化により、高いパフォーマンスとスケーラビリティを持つ Python サービスを実現します。これにより、Python で開発されたサービスは、従来の FastAPI や Flask よりも大幅に高いスループットと低いレイテンシを実現し、JVM エコシステムの成熟したフレームワークを活用できるようになります。また、Micronaut Data によるビルド時 SQL クエリ生成や、Java ライブラリとのシームレスな連携も可能です。
全文翻訳
← Blog
Pyronaut の紹介
2026年10月2日
Graeme Rocher
発表
本日、GraalVM と Micronaut を基盤とした、本番環境対応サービス構築のための高性能 Python アプリケーションプラットフォームである Pyronaut の提供開始を発表できることを嬉しく思います。
Pyronaut とは?
Pyronaut は、Python AST を Java コンパイラと融合させ、GraalVM と Graal JIT による実行時最適化により、非常に高性能でスケーラブルな Python サービスを可能にすることで、Micronaut と GraalVM (AOT コンパイル、ビルド時検証、ソースコード処理など) の同じアイデアとメリットを Python にもたらします。AI の成長のおかげで、Python は今日、世界で最も人気のある言語の 1 つであり、今日から Python は、JVM エコシステムで最も成熟し、スケーラブルで人気のあるフレームワークの 1 つ上で使用できるようになります。サーバーサイド言語として Python を選択することは、もはやスループットの低下とレイテンシの増加を意味しません。
最小の Pyronaut アプリケーション
main.py を作成:
from micronaut.http.annotation import Get
@Get("/")
def read_root() -> dict:
return {"Hello": "World"}
@Get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None) -> dict:
return {"item_id": item_id, "q": q}
実行:
pyronaut dev main.py
デプロイ:
pyronaut run main.py
スケーラビリティ
Netty によるパワーアップ
Micronaut は、あらゆる言語で世界で最もスケーラブルで高性能な非同期フレームワークの 1 つである Netty を基盤としています。Pyronaut では、Python コードは同じ Netty ベースの HTTP サーバーによって提供され、Graal JIT によって最適化されます。当社のベンチマークでは、これは FastAPI の 2.6 倍のスループットと Flask の 6.5 倍のスループットを、より低いレイテンシで実現することを意味します (この投稿の後半で詳しく説明します)。
Python の asyncio パイプラインを Netty イベントループに直接接続したため、非同期/await をネイティブに使用して、スケーラブルなノンブロッキングサービスを記述できます。
import asyncio
from micronaut.http.annotation import Get
@Get("/slow-hello")
async def slow_hello() -> str:
await asyncio.sleep(0.5) # コルーチンを中断しますが、イベントループは中断しません
return "hello"
asyncio.run() も uvicorn もありません。Pyronaut が関数を呼び出すときにはすでにイベントループが存在しており、asyncio.gather や asyncio.TaskGroup は期待どおりに機能します。
これをストリーミングに拡張したため、SSE、websockets、その他のユースケースのストリーミングサービスを記述するために async を使用できます。yield を含む任意の async def ルートは、バックプレッシャーでクライアントにストリーミングバックされます。
from dataclasses import dataclass
from typing import AsyncIterator
from java.time import Duration
from micronaut.http import MediaType
from micronaut.http.annotation import Get
from micronaut.sse import Event
from micronaut_asyncio import as_async_iterable
from reactor.core.publisher import Flux
@Serdeable
@dataclass
class Tick:
index: int
label: str
@Get(value="/ticks", produces=MediaType.TEXT_EVENT_STREAM)
async def ticks() -> AsyncIterator[Event[Tick]]:
every_second = Flux.interval(Duration.ofSeconds(1)).take(3)
async with as_async_iterable(every_second) as seconds:
async for second in seconds:
yield Event.of(Tick(second, f"tick-{second}"))
Java ライブラリ (Reactor など) がネイティブ Python async/await で「そのまま動作する」ように、任意のリアクティブ Publisher または Java CompletableFuture を await で活用できます。たとえば、組み込みの Micronaut HttpClient を使用して、async/await でノンブロッキング REST 呼び出しを行うことができます。
from dataclasses import dataclass
from typing import Annotated
from jakarta.inject import Inject
from micronaut.http import HttpRequest
from micronaut.http.annotation import Get
from micronaut.http.client import HttpClient
from micronaut.http.client.annotation import Client
from micronaut.serde.annotation import Serdeable
@Serdeable
@dataclass
class Repo:
name: str
stargazers_count: int
github: Annotated[HttpClient, Inject, Client("https://api.github.com")]
@Get("/repos/{owner}/{name}")
async def repo(owner: str, name: str) -> Repo:
request = HttpRequest.GET(f"/repos/{owner}/{name}").header("User-Agent", "pyronaut")
return await github.retrieve(request, Repo)
データアクセス
Micronaut Data
ほとんどの Python Web フレームワークでは、データアクセスは開発者に任されています。ORM を選択し、セッションを配線し、クエリが実際に機能するかどうかを実行時に確認します。Pyronaut には Micronaut Data が含まれており、Python でリポジトリを定義でき、お気に入りのデータベース用の SQL クエリをビルド時に事前計算します。実行時のクエリ変換はなく、存在しないプロパティを参照するクエリは、本番環境でのリクエストではなくビルド時に失敗します。
from dataclasses import dataclass
from typing import Annotated
from jakarta.inject import Inject
from jakarta.transaction import Transactional
from micronaut.data.annotation import GeneratedValue, Id, MappedEntity, Query
from micronaut.data.jdbc.annotation import JdbcRepository
from micronaut.data.model import Page, Pageable
from micronaut.data.repository import CrudRepository
from micronaut.http.annotation import Body, Get, Post
from micronaut.serde.annotation import Serdeable
@Serdeable
@MappedEntity
@dataclass
class Rocket:
id: Annotated[int | None, Id, GeneratedValue]
name: str
thrust: float
@JdbcRepository(dialect="ORACLE")
class RocketRepository(CrudRepository[Rocket, int]):
def findByNameContains(self, fragment: str) -> list[Rocket]: ...
def findTop3ByThrustGreaterThanOrderByThrustDesc(self, thrust: float) -> list[Rocket]: ...
def findNameByThrustLessThan(self, thrust: float) -> list[str]: ...
def findAll(self, pageable: Pageable) -> Page[Rocket]: ...
@Query("SELECT * FROM rocket WHERE LOWER(name) LIKE LOWER(:pattern)")
def search(self, pattern: str) -> list[Rocket]: ...
def update(self, id: Annotated[int, Id], thrust: float) -> None: ...
rockets: Annotated[RocketRepository, Inject]
@Post("/rockets")
@Transactional
def launch(fleet: Annotated[list[Rocket], Body]) -> list[Rocket]:
return [rockets.save(rocket) for rocket in fleet]
@Get("/rockets/strongest/{thrust}")
def strongest(thrust: float) -> list[Rocket]:
return rockets.findTop3ByThrustGreaterThanOrderByThrustDesc(thrust)
@Get("/rockets/page/{number}")
def page(number: int) -> Page[Rocket]:
return rockets.findAll(Pageable.from_(number, 2))
派生ファインダー、プロジェクション、ページネーション、明示的なクエリ、部分更新、トランザクションはすべて標準で提供されます。
$ curl http://localhost:8080/rockets/strongest/5000
[{"id":5,"name":"Starship","thrust":74000.0},{"id":1,"name":"Saturn V","thrust":35100.0},{"id":3,"name":"Ariane 6","thrust":10400.0}]
同じプログラミングモデルは、JDBC、R2DBC、Hibernate/JPA、Hibernate Reactive、MongoDB、Azure Cosmos DB で動作するため、Python 開発者は長年 Micronaut ユーザーが信頼してきたのと同じ成熟したデータアクセス層を利用できます。
Python と javac の結婚
Pyronaut は Python のソースコードプロセッサであり、Python ソースを分析し、Java アノテーションを見るたびに Python デコレータを自動的に表面化します。このアプローチにより、ビルド時検証や先行コンパイルを含む、成熟した Micronaut フレームワークコア全体を Python 言語にもたらすことができました。実際には、Micronaut のすべての部分が Python で「そのまま動作」し、Python 開発者はプラットフォーム全体に完全にアクセスできます。
Micronaut Serialization を使用してシリアライズ可能なデータクラスを記述できます。これは、高速で効率的な JSON シリアライズ/デシリアライズを提供するビルド時シリアライザ/デシリアライザを計算します。
from dataclasses import dataclass
from typing import Annotated
from com.fasterxml.jackson.annotation import JsonProperty
from micronaut.serde.annotation import Serdeable
@Serdeable
@dataclass
class Book:
title: str
quantity: Annotated[int, JsonProperty("qty")]
Micronaut ルート (Python で定義) からビルド時に OpenAPI 仕様を生成できます。ドキュメンテーション文字列は API を説明するために使用されます。
from io.swagger.v3.oas.annotations import OpenAPIDefinition
from io.swagger.v3.oas.annotations.info import Info
from micronaut.http.annotation import Get
OpenAPIDefinition(info=Info(title="Greeting