docs: 添加 handler 中使用 threading.Thread 的注意事项
This commit is contained in:
44
README.md
44
README.md
@@ -186,6 +186,50 @@ def slow_compute(n: int) -> int:
|
|||||||
|
|
||||||
> 限制:长时间不释放 GIL 的 C 扩展(如大规模 numpy 矩阵运算)无法被中断,需等其释放 GIL 后才触发。
|
> 限制:长时间不释放 GIL 的 C 扩展(如大规模 numpy 矩阵运算)无法被中断,需等其释放 GIL 后才触发。
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
### 在 handler 中使用 `threading.Thread`
|
||||||
|
|
||||||
|
handler 函数内部可以启动后台线程,但行为取决于是否等待:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# ✅ fire-and-forget:立即返回,连接立即释放,后台线程独立运行
|
||||||
|
@expose
|
||||||
|
def do_something():
|
||||||
|
threading.Thread(target=long_task, daemon=True).start()
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
# ⚠️ 等待线程:连接被占用直到线程结束,等同于直接在 handler 里执行
|
||||||
|
@expose
|
||||||
|
def do_something():
|
||||||
|
t = threading.Thread(target=long_task)
|
||||||
|
t.start()
|
||||||
|
t.join() # 连接在此阻塞
|
||||||
|
return "ok"
|
||||||
|
```
|
||||||
|
|
||||||
|
**`call_go()` 只能在 handler 的原始线程中调用。** `call_go()` 依赖线程局部变量 `_local.mux` 获取当前连接,后台线程中该变量不存在,调用会抛出 `RuntimeError`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@expose
|
||||||
|
def do_something():
|
||||||
|
def bg():
|
||||||
|
call_go("Method") # ❌ RuntimeError: call_go() must be called within a gobridge handler
|
||||||
|
threading.Thread(target=bg, daemon=True).start()
|
||||||
|
return "ok"
|
||||||
|
```
|
||||||
|
|
||||||
|
如果后台线程的结果需要回调 Go,应在 handler 线程中通过 `queue.Queue` 等待后台线程结果后再调用:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@expose
|
||||||
|
def do_something():
|
||||||
|
result_q = queue.Queue()
|
||||||
|
threading.Thread(target=lambda: result_q.put(compute()), daemon=True).start()
|
||||||
|
result = result_q.get() # 等待后台线程
|
||||||
|
return call_go[str]("Process", result) # ✅ 在 handler 线程中调用
|
||||||
|
```
|
||||||
|
|
||||||
## 进程自动重启
|
## 进程自动重启
|
||||||
|
|
||||||
Python worker 进程崩溃时自动重启,调用方无感知:
|
Python worker 进程崩溃时自动重启,调用方无感知:
|
||||||
|
|||||||
Reference in New Issue
Block a user