Skip to content
[OPEN_POKER]

为什么你的Poker Bot超时:原因与异步修复

JJoão Carvalho||4 min read

Poker bot超时会自动弃掉你正在持有的任何手牌。口袋A、坚果同花——无所谓:服务器没收操作,你的筹码倒退。120秒窗口听起来很宽裕,直到你看到真正的bot在会话第47手就用完了。以下是原因和每种情况的修复方法。

bot超时会发生什么?

Open Poker强制从your_turn到你发送有效action消息有120秒的硬性窗口。超时则服务器强制弃牌(或过牌)。bot留在桌上但手牌丢失。重复超时会导致断开连接。完整行为见操作超时参考

超时倾向于发生在你最强的手牌上。Bot在重要决策上思考得更久。

为什么120秒实际上并不宽裕?

1. 决策循环中的同步网络调用。 第一大原因。每个同步调用阻塞整个bot。

2. 决策期间的重连。

3. 长时间运行bot的垃圾回收暂停。

如何找到慢决策?

import time
 
async def handle_your_turn(msg, ws):
    start = time.monotonic()
    try:
        action = await decide(msg)
        await ws.send(json.dumps({
            "type": "action",
            "action": action["type"],
            "amount": action.get("amount", 0),
            "client_action_id": f"a-{msg['turn_token'][:8]}",
            "turn_token": msg["turn_token"],
        }))
    finally:
        elapsed_ms = (time.monotonic() - start) * 1000
        if elapsed_ms > 1000:
            print(f"[SLOW] decision took {elapsed_ms:.0f}ms on hand {msg.get('hand_number')}")

如何修复同步网络调用?

全部转为async。用httpx替代requests

import httpx
http = httpx.AsyncClient(timeout=3.0)
 
async def decide(msg):
    response = await http.get("https://api.example.com/equity")
    equity = response.json()["equity"]
    return ("call" if equity > 0.4 else "fold")

如何给决策加超时保护?

async def decide_with_fallback(msg):
    try:
        return await asyncio.wait_for(decide(msg), timeout=10.0)
    except asyncio.TimeoutError:
        return fallback_decision(msg)
 
def fallback_decision(msg):
    actions = {a["action"]: a for a in msg["valid_actions"]}
    if "check" in actions:
        return ("check", 0)
    if "call" in actions:
        call_amt = actions["call"]["amount"]
        if call_amt < msg.get("pot", 0) * 0.2:
            return ("call", call_amt)
    return ("fold", 0)

如何处理重连?

while True:
    try:
        async with websockets.connect(WS_URL, additional_headers=headers) as ws:
            await ws.send(json.dumps({"type": "set_auto_rebuy", "enabled": True}))
            await ws.send(json.dumps({"type": "join_lobby", "buy_in": 2000}))
            async for raw in ws:
                msg = json.loads(raw)
                await handle_message(msg, ws)
    except websockets.ConnectionClosed:
        print("Connection lost, reconnecting in 2s...")
        await asyncio.sleep(2)

FAQ

Open Poker的操作超时是多少? 120秒。超时自动弃牌。

为什么bot只在难决策时超时? 因为复杂决策触发更多代码路径。

可以延长超时吗? 不能。120秒对所有bot固定。

合理的目标延迟是多少? 200ms以下优秀。5秒以上需要调查。


超时是摧毁bot胜率的隐形bug。修复主要是防御性的:记录每次决策延迟,用asyncio.wait_for()包装主逻辑,处处使用async客户端,并有安全的fallback。从一开始就用这些模式构建你的第一个bot,你就永远不需要在生产环境中调试超时了。

继续阅读