feat: 添加 Python→Go 全双工回调支持(call_go)

- 新增 WithHandlers 选项,通过反射将 Go 结构体方法暴露给 Python
- 新增 callback/callback_result 消息类型,支持 Python 在处理中回调 Go
- client 侧新增 readResult,内联处理 callback,复用同一连接避免死锁
- Python 侧新增 call_go[T]() 泛型调用,支持 dataclass 自动构造
- 注入 GOBRIDGE_WORKER_ID/WORKER_COUNT 环境变量,支持多 worker 初始化分工
- 新增示例演示 Go→Python→Go→Python 四层全双工链路
- Python 包版本升至 0.1.1
This commit is contained in:
2026-04-14 13:06:50 +08:00
parent 07e9239ac5
commit b390effd8e
8 changed files with 490 additions and 54 deletions

View File

@@ -2,9 +2,24 @@ import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "python"))
from gobridge import expose, run
import dataclasses
import threading
from typing import Iterator
from gobridge import expose, call_go, run, worker_id, worker_count
# ── worker_id / worker_count ──────────────────────────────────────────────────
# 只有 worker 0 才执行一次性初始化(如监听端口、建立长连接等),
# 其余 worker 跳过,避免端口冲突 / 重复连接。
print(f"[worker {worker_id}/{worker_count}] started", flush=True)
if worker_id == 0:
def _init_shared_resource():
# 示例:此处可启动 WebSocket 客户端、监听 TCP 端口等
print(f"[worker {worker_id}] shared resource initialized", flush=True)
threading.Thread(target=_init_shared_resource, daemon=True).start()
# ── 基础类型 ─────────────────────────────────────────────────────────────────
@expose
def add(a: int, b: int) -> int:
@@ -26,12 +41,20 @@ def sum_stream(numbers: Iterator[int]) -> int:
@expose
def double_stream(numbers: Iterator[int]) -> Iterator[int]:
"""双向流输入每个数yield 其平方,对应 Go 侧 Invoke[chan int](c, ctx, "double_stream", inputChan)"""
"""双向流输入每个数yield 其平方"""
for n in numbers:
yield n * n
# ── structdict类型 ──────────────────────────────────────────────────────
# ── structdataclass / dict类型 ───────────────────────────────────────────
@dataclasses.dataclass
class User:
id: int
name: str
score: float
level: str = ""
@expose
def get_user(uid: int) -> dict:
@@ -56,8 +79,6 @@ def enrich_users(users: list) -> list:
return result
# ── struct/slice 流式组合 ────────────────────────────────────────────────────
@expose
def gen_users(count: int) -> Iterator[dict]:
"""流式输出 structyield 多个 User对应 Go 侧 Invoke[chan User]"""
@@ -72,4 +93,48 @@ def process_users(users: Iterator[dict]) -> Iterator[dict]:
yield {"id": u["id"], "name": u["name"].upper(), "score": u["score"] * 2}
# ── Server 全双工示例 ────────────────────────────────────────────────────────
@expose
def compute_with_go_mul(a: int, b: int) -> int:
"""示例1call_go[int] 指定返回类型"""
return call_go[int]("Multiply", a, b)
@expose
def squared_with_log(n: int) -> Iterator[int]:
"""示例2流式输出每次 yield 前 call_go("Log") 回调 Go"""
for i in range(1, n + 1):
call_go("Log", f"yielding {i}² = {i * i}")
yield i * i
@expose
def to_upper(s: str) -> str:
"""辅助方法:被 Go 的 EnrichName handler 内部调用"""
return s.upper()
@expose
def full_chain(name: str) -> str:
"""示例3Go→Python→Go→Python 四层链路
full_chain("world")
→ call_go[str]("EnrichName", "world") # Python 调 Go
→ Invoke[string](ctx, serv, "to_upper", "world") # Go 再调 Python
"WORLD"
"Hello, WORLD!"
"Hello, WORLD!"
"""
return call_go[str]("EnrichName", name)
@expose
def get_user_via_go(uid: int) -> dict:
"""示例4call_go[User] 自动将 Go 返回的 dict 构造为 dataclass 实例"""
user = call_go[User]("MakeUser", uid) # Go 返回 {"id":..,"name":..,"score":..}
user.level = "gold" if user.score >= 10 else "silver"
return dataclasses.asdict(user)
run()