You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在现有Python程序中集成asyncio SSH服务并实现变量共享

解决方案

你遇到的问题本质是asyncio的事件循环为单线程调度,原来的同步while循环带time.sleep会阻塞整个事件循环,导致SSH服务和主循环无法同时运行,解决方法分两种场景:


场景1:原有主循环可修改为异步逻辑(推荐)

该方案无需引入多线程,全局变量读写无并发安全问题,实现成本最低。

修改步骤

  • 将原有同步主循环改造为异步协程,把所有time.sleep替换为asyncio.sleep,避免阻塞事件循环
  • 在SSH服务启动后,将主循环协程通过loop.create_task提交到事件循环中调度
  • 全局变量可直接在handle_client和主循环中读写,单线程协程调度不会出现竞态问题

修改后完整代码示例:

import asyncio, asyncssh, sys
# 原有依赖库正常导入即可
is_open = True
return_value = 0

async def handle_client(process):
    global is_open, return_value
    process.stdout.write('Enter numbers one per line, or EOF when done:\n')
    # 注意布尔值需要转字符串才能写入stdout,否则会报错
    process.stdout.write(f"当前is_open值:{is_open}\n")

    total = 0
    try:
        async for line in process.stdin:
            line = line.rstrip('\n')
            # 举个修改变量的例子:输入open/close可直接修改全局变量
            if line == 'open':
                is_open = True
                process.stdout.write("已修改is_open为True\n")
                continue
            if line == 'close':
                is_open = False
                process.stdout.write("已修改is_open为False\n")
                continue
            if line:
                try:
                    total += int(line)
                except ValueError:
                    process.stderr.write('Invalid number: %s\n' % line)
    except asyncssh.BreakReceived:
        pass

    process.stdout.write('Total = %s\n' % total)
    process.exit(0)

# 改造后的异步主循环
async def main_loop():
    global return_value
    while True:
        # 原有业务逻辑直接放在这里即可,所有time.sleep替换为asyncio.sleep
        print(f"主循环运行中,return_value={return_value}, is_open={is_open}")
        return_value += 1
        await asyncio.sleep(0.1)

async def start_server():
    await asyncssh.listen('', 8022, server_host_keys=['key'],
                          authorized_client_keys='key.pub',
                          process_factory=handle_client)
    # 提交主循环协程到事件队列调度
    asyncio.create_task(main_loop())

loop = asyncio.get_event_loop()

try:
    loop.run_until_complete(start_server())
except (OSError, asyncssh.Error) as exc:
    sys.exit('Error starting server: ' + str(exc))

loop.run_forever()

场景2:原有主循环逻辑复杂,无法改造为异步

如果原有主循环包含大量阻塞同步调用、GPIO操作等无法异步改造的逻辑,可以将主循环放到独立线程中运行,此时读写全局变量需要加线程锁避免竞态。

修改要点

  • 引入threading.Lock作为全局变量的读写锁,所有读写全局变量的位置都要先加锁
  • 用threading.Thread启动独立线程运行原有同步主循环

关键代码片段示例:

import threading, time

lock = threading.Lock()
is_open = True
return_value = 0

# handle_client中读写变量的写法
async def handle_client(process):
    global is_open
    # 读变量
    with lock:
        current_is_open = is_open
    process.stdout.write(f"当前is_open值:{current_is_open}\n")
    # 写变量
    with lock:
        is_open = False

# 原有同步主循环不用修改,仅增加锁逻辑即可
def sync_main_loop():
    global return_value
    while True:
        with lock:
            print(f"主循环运行中,return_value={return_value}, is_open={is_open}")
            return_value +=1
        time.sleep(0.1)

if __name__ == "__main__":
    # 启动服务前先启动主循环线程
    threading.Thread(target=sync_main_loop, daemon=True).start()
    # 后面原有SSH启动逻辑保持不变

内容的提问来源于stack exchange,提问作者user105939

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 04:57:06